Hi Glenn, This is pretty good! I added some remarks below:
On Wed, Jun 21, 2017 at 3:48 PM, Glenn Hoetker <[email protected]> wrote: > > ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; > #lang racket > > (define in (open-input-file "/Users/me/BibDeskPapers/oldBib.bib")) > (define out (open-output-file "/Users/me/BibDeskPapers/newBib.bib" #:exists > 'replace)) > (define keyword-prefix "\tKeywords = {") > > ;; Return a string with only the first word capitalized and all else in lower > case > ;; Courtesy https://groups.google.com/forum/m/#!topic/racket-users/gw8Ivm5HSZQ > (provide > (contract-out > [string-upcase-first-word (-> string? string?)])) If you want your use of `string-upcase-first-word` to be protected by this contract, then you'll either need to: - provide it, like you do here, from a *different* module, and require it in this one, or - define the function in this module with `define/contract`. What you're doing: (provide (contract-out ...)) ... means that other modules that require this one will get the contract-protected version of the function, but within this module, the function has no contract. You can read about contract boundaries here [http://docs.racket-lang.org/guide/contract-boundaries.html]. > > (define (string-upcase-first-word s) > (apply > string > (for/list ([c (in-string s)] > [i (in-naturals)]) > (if (= i 0) > (char-upcase c) > (char-downcase c))))) > > (module+ test > (require rackunit) > (check-equal? (string-upcase-first-word "") "") > (check-equal? (string-upcase-first-word "Cat Dog") "Cat dog") > (check-equal? (string-upcase-first-word "cat dog") "Cat dog")) > > ;; Main program > (for ([aLine (in-lines in)]) Racketeers typically use hyphen-delimited identifiers instead of camel case (though in this particular situation, I think it would be more common to use `line` instead of either `aLine` or `a-line`). > (cond > [(string-prefix? aLine "\tKeywords = {") ; Identify Keywords lines > (define keywords-as-list (string-split (string-replace aLine "\tKeywords > = {" "") ",")) > (define cleaned-keywords (map (lambda (aString) > (string-upcase-first-word > (string-trim aString))) > keywords-as-list)) > (display keyword-prefix out) > (display (string-join cleaned-keywords ", ") out) > (display "," out) > (newline out)] > [else (display aLine out) (newline out)])) Usually, you'd put separate sequential expressions on separate lines. Since the second expression is just meant to add a newline to the end of the string you just displayed, you can use `displayln` instead: [else (displayln line)] > > ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; One general piece of advice: abstract your main loop into a procedure that accepts input and output ports. That will make it much easier to test. I gave some thought to how I'd accomplish the same thing and came up with the following. This version assumes you're going to read the entire file into memory as a string. Of course, you can substitute your favorite version of the capitalization procedure: #lang at-exp racket ;; normalize-keywords: string? -> string? #lang at-exp racket (define (normalize-keywords in) (regexp-replace* @pregexp|{Keywords ?= ?\{\s*([^}]*)\}}| in (λ (_ s) (string-join (map capitalize-first (regexp-split #px", *" s)) ", ")))) (define (capitalize-first s) (cond [(non-empty-string? s) (string-append (string-upcase (substring s 0 1)) (string-downcase (substring s 1)))] [else ""])) -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.

