Best way to do input with racket?
Asked Answered
A

4

11

What's the best way to read input from stdin in racket?

In particular I'd like something like cin from c++ or scanf from c where I specify the types of things I want read and they are returned.

Allard answered 14/11, 2011 at 10:5 Comment(0)
H
8

You can do pretty much everything you want to... at the low level, I would suggest (read-line) and (read-bytes). For higher-level processing (as e.g. scanf does), I would suggest a regexp-match on the input. For instance

(regexp-match #px" *([0-9]+)" (current-input-port))
Helicograph answered 14/11, 2011 at 22:49 Comment(0)
S
10

read-line is easy. To be portable across Unix and Windows, additional option is required.

(read-line (current-input-port) 'any)

Return and linefeed characters are detected after the conversions that are automatically performed when reading a file in text mode. For example, reading a file in text mode on Windows automatically changes return-linefeed combinations to a linefeed. Thus, when a file is opened in text mode, 'linefeed is usually the appropriate read-line mode.

So, 'any is required to be portable when the input port is not a file (standard input).

Test program:

#lang racket
(let loop ()
    (display "Input: ")
    (define a (read-line (current-input-port) 'any))
    (printf "input: ~a, length: ~a, last character: ~a\n"
        a
        (string-length a)
        (char->integer (string-ref a (- (string-length a) 1))))
    (loop))

In Windows, replace (read-line (current-input-port) 'any) with (read-line) and see what happens.

Sporogenesis answered 19/1, 2014 at 14:17 Comment(2)
Actually, read-line should be portable across Unix and Windows without setting different options (mentioned further down in the docs).Thierry
This results in: ; string-ref: contract violation ; expected: exact-nonnegative-integer? ; given: -1 ; argument position: 2nd ; other arguments...: ; "" ; Context: ; stdin:1:1 loop (Racket 6.10.1)Jezreel
H
8

You can do pretty much everything you want to... at the low level, I would suggest (read-line) and (read-bytes). For higher-level processing (as e.g. scanf does), I would suggest a regexp-match on the input. For instance

(regexp-match #px" *([0-9]+)" (current-input-port))
Helicograph answered 14/11, 2011 at 22:49 Comment(0)
C
2

I'd use the read procedure for the general case. If the data type to be read is known beforehand, use read-char, read-string, read-bytes.

Also, take a look at this implemenation for reading formatted input - a scanf in Scheme.

Cutout answered 14/11, 2011 at 13:52 Comment(5)
Read seems to have problems if there are parentheses in the inputAllard
What kind of problems? it works fine for me, a parenthesized expression is returned as a list of symbols - as expected. And did you look at the library I linked? it's like scanf but in SchemeSpeculator
For example, try using this as your input: ( 1 2 3. Then call (read) (read) (read) (read). Instead of yielding four strings ((, 1, 2, 3), it yields an error. The library looks great - thanks! I was hoping to find something built-in so I can see what the standard practice is for this sort of thing. John Clements' answer was what I was looking for. I understand what read does - it's just not what I was looking for.Allard
@ÓscarLópez bad link :cPolychasium
@Polychasium I updated it with a similar link, the original is gone for good :(Speculator
F
0

Here's a basis for line-by-line processing in Racket Scheme. It doesn't split an input line into multiple words, or do typed input, but this seems like a good place to put it.

(define (get)
  (read-line (current-input-port)))

(define (put . vs)
  (for-each display vs)
  (displayln ""))

(define (sed fn)
  (let ((line (get)))
    (if (not (eof-object? line))
      (begin
        (fn line)
        (sed fn))
      'true)))

(sed (lambda (line)
  (put "Hello, " line)))

Here's one that does split input, also encodes CSV for good measure.

(define (get)
  (read-line (current-input-port)))

(define split string-split)
(define sep ",")
(define enc identity)

(define (enc-csv s)
  (string-append "\"" (string-replace s "\"" "\"\"") "\""))
(define enc enc-csv)

(define (put . vs)
  (displayln (string-join (map enc vs) sep)))

(define (sed fn)
  (let ((line (get)))
    (if (not (eof-object? line))
      (begin
        (fn line)
        (sed fn))
      'true)))

(sed (lambda (line)
  (apply put (split line))))

This works in Racket. I'm not sure how much of it is specific to Racket. It doesn't seem to work in Chicken or Guile.

Farci answered 4/5, 2021 at 17:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.