With help from this group, I've written my first baby-program in Racket and 
would really appreciate any feedback on how to make it more idiomatic, 
efficient and well-formatted (I struggle with where to break lines). Thank you 
in advance.

The purpose is to fix the irregular capitalization of entries in the "Keywords" 
field of a large BibLaTeX (.bib) file. A sample entry in the input file might be

@article{Ender-2016-Review-00,
        Author = {Ender, P. B.},
        Keywords = {Book Review, Behaviorial sciences, ANALYSIS OF VARIANCE, 
experimental design},
        ...}

I want non-Keyword lines passed unchanged to the output file and each keyword 
entry (potentially multiword) changed to have only its first word capitalized. 
Thus

@article{Ender-2016-Review-00,
        Author = {Ender, P. B.},
        Keywords = {Book review, Behaviorial sciences, Analysis of variance, 
Experimental design},
        ...}


Here is what I came up with.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#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?)])) 

(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)])
  (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)]))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Thank you again.

-- 
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