Hi Glenn,

This is pretty good! I added some remarks below:

On Wed, Jun 21, 2017 at 3:48 PM, Glenn Hoetker <ghoet...@gmail.com> 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 racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to