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.
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.
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))
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.
; 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 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))
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.
scanf
but in Scheme –
Speculator ( 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 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.
© 2022 - 2024 — McMap. All rights reserved.
read-line
should be portable across Unix and Windows without setting different options (mentioned further down in the docs). – Thierry