2013-11-08 4 views
0

MIT Scheme имеет string->input-port, Racket имеет open-input-string. Как реализовать это в чистой схеме (без Racket, Chicken, Gambit или любого расширения, специфичного для реализации).Преобразование кода в/из строки

+0

В какой версии вы нацеливаетесь. Текущий R6RS или старый R5RS? – Sylwester

ответ

1

Согласно Chis' answer, у нас есть новый стандарт схемы, R7RS. Он имеет open-input-string.

Для старых R6RS тривиально реализовать то же самое с make-custom-textual-input-port от (rnrs io ports (6)) библиотеки. Вот что-то я соединял:

#!r6rs 

(import (rnrs base (6)) 
     (rnrs io ports (6)) 
     (rnrs mutable-strings (6)) 
     (rnrs io simple (6))) 

(define (open-input-string str) 
    ;; might not be so important to have a different indentifier 
    ;; but this will make debugging easier if implementations use the 
    ;; id provided 
    (define get-id 
    (let ((n 0)) 
     (lambda (str) 
     (set! n (+ n 1)) 
     (string->symbol 
     (string-append "string-port" str "-" 
         (number->string n)))))) 

    (let ((len (string-length str)) 
     (pos 0)) 
    (make-custom-textual-input-port 
    (get-id str) 
    (lambda (string start count) 
     (let loop ((cur-dst start) 
        (cur-src pos) 
        (n 0)) 
     (cond ((or (>= cur-src len) 
        (>= n count)) 
       (set! pos cur-src) 
       n) 
       (else 
       (string-set! string cur-dst (string-ref str cur-src)) 
       (loop (+ cur-dst 1) 
         (+ cur-src 1) 
         (+ n 1)))))) 
    (lambda() pos) 
    (lambda (new-pos) (set! pos new-pos)) 
    #f))) 

(define test (open-input-string "(1 2 3 4)(5 6 7 8)")) 
(define str (read test)) ; str == (1 2 3 4) 
(define str2 (read test)) ; str2 == (5 6 7 8) 

С R5RS не существует способ сделать это, за исключением использования файла.

+0

Хорошо, давайте сделаем одно лучше: R7RS недавно был ратифицирован, и у него есть 'open-input-string' встроенный. ;-) –

+0

@ ChrisJester-Young Я буду использовать его, у второго Ikarus и Racket есть поддержка для него :) – Sylwester

-2

Написать строку в (временный) файл, а затем возвращает входной порт, чтобы прочитать его обратно в Как это:.

(define (open-input-string string) 
    (let ((file "/tmp/foo")) 
    (call-with-output-file file 
     (lambda (port) 
     (display string port))) 
    (open-input-file file))) 

> (define ps (open-input-string "This is a test; it is only a test")) 
> ps 
#<input-port (textual) "/tmp/foo"> 
> (read-line ps) 
"This is a test; it is only a test" 

Обратите внимание, вы должны быть более сложными с использованием file. Например, приведенный выше код работает только один раз; он будет терпеть неудачу с «файлом существует» во втором вызове. Но вышесказанное является простым ответом на ваш вопрос.

+0

Запись в фиксированный файл temp очень небезопасна, так как открывает возможности для [атаки символической ссылки] (http://en.wikipedia.org/wiki/Symlink_race). Чтобы быть в безопасности, вам придется использовать 'mkstemp', который не является« чистой схемой ». –

+0

Спасибо. Здесь не решаются проблемы мира; просто отвечая на вопрос для нуждающегося человека. – GoZoner

+1

Возможно, но это все еще плохое решение, похожее на то, что кто-то использует 'gets' (в C) для чтения в строке из stdin. –

1

В недавно ратифицированном R7RS, open-input-string предоставляется непосредственно. (Благодаря Сильвестер за напоминание мне смотреть за R5RS. :-))


В R5RS, чистая Схема реализации строковых портов не является тривиальной, так как она требует, чтобы переопределить все функции ввода/вывода стандарта , См. SRFI 6 для справочной реализации.

Это действительно лучше, если ваша реализация поддерживает строковые порты напрямую.

Смежные вопросы