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.

Reply via email to