0

If Guile is not the best Scheme for this usage, then which one should I be looking at? I'm basically looking for a Guile equivalent of awk '{print $N}'. If Scheme can't do this, then I'd like to know why not.

takatakatek
  • 103
  • 2
  • You could do this in pure Scheme, but it would probably be obnoxious because there isn’t much of a standard library. Here’s a Racket one-liner that does it, though: `(for ([l (in-lines)]) (displayln (second (string-split l))))`. – Alexis King Sep 07 '17 at 23:19
  • @AlexisKing I'm willing to accept this as an answer, but it would be great to see alternatives in other dialects. That is less obnoxious than I might have imagined. It's certainly preferable to the equivalent C code presented by Brian Kernighan. Is the *for* macro available in other Schemes? What is *in-lines*? – takatakatek Sep 08 '17 at 02:41
  • No, [`for`](http://docs.racket-lang.org/reference/for.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._for%29%29) in its precise form is a Racket-specific feature, as is [`in-lines`](http://docs.racket-lang.org/reference/sequences.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._in-lines%29%29). The latter is a constructor for a Racket “sequence” that iterates through the lines in a port. If no port is given, it defaults to `(current-input-port)`, aka stdin. – Alexis King Sep 08 '17 at 03:34
  • @AlexisKing I see. Would you recommend Racket over other Schemes if I intend to frequently do text processing, among other tasks? – takatakatek Sep 08 '17 at 13:23

2 Answers2

0

At my blog I have an essay giving a set of functions that make it easy to handle delimited text files.

user448810
  • 17,381
  • 4
  • 34
  • 59
0

Guile changed its I/O a bit between 2.0 and 2.2, so this uses r6rs I/O which (hopefully) works the same in both, but I haven't tested with 2.2.

This can be optimized further.

#!/usr/bin/guile \
-e start -s
!#

(use-modules (rnrs io ports))

;;; Reads one line from current-input-port and prints the field indicated by
;;; field-num.  If the line does not have enough fields, it prints a newline.
;;; Returns the field, an empty string, or #f if end of file is reached.
(define (get-field field-num)
  (let ((line (get-line (current-input-port))))
    (if (eof-object? line)
        #f
        (let ((fields (string-tokenize line)))
          (if (< field-num (length fields))
              (let ((field (list-ref fields field-num)))
                (put-string (current-output-port)
                            (string-append field "\n"))
                field)
              (and (put-string (current-output-port) "\n")
                   ""))))))

;;; Repeat get-field until until end of file is reached
(define (get-all-fields field-num)
  (if (get-field field-num)
      (get-all-fields field-num)
      #f))

(define (start args)
  (if (and (> (length args) 1)
           (integer? (string->number (list-ref args 1))))
      (get-all-fields (1- (string->number (list-ref args 1))))
      (display (string-join
                `("Usage:" ,(list-ref args 0) "<field-number>\n")
                " "))))
Jeff Spaulding
  • 223
  • 3
  • 8
  • This seems to work, and should prove helpful. Why the line continuation in the shebang line? Thanks. – takatakatek Sep 19 '17 at 11:15
  • That's what it recommends in the Guile manual. Apparently, POSIX is silent about shebang lines, and you get mixed results if you have more than one thing after the command. If I understand it correctly, using a continuation when there's more than one argument is "more portable" in practice. – Jeff Spaulding Sep 19 '17 at 15:36