如何在球拍中读取空格分隔的整数

时间:2017-05-24 20:19:15

标签: racket

我查看了文档https://docs.racket-lang.org/reference/input-and-output.html,但我发现它非常令人困惑,我觉得它包含了很多额外的信息,我不需要这么简单的任务。

我想读取两个空格分隔的整数并将它们存储在变量中。

示例输入:

1 2

我想定义x和y,其值分别为1和2。

1 个答案:

答案 0 :(得分:1)

有一些很多方法可以做到这一点。我会给你三个。

选项1:使用内置read

read函数读取s表达式。方便的是,整数是有效的s表达式,它也会跳过空格。这意味着您只需在输入端口上调用read两次即可生成两个基准:

> (let ([in (open-input-string "1 2")])
    (values (read in) (read in)))
1
2

这有一个缺点:有很多东西都是不是数字的有效s表达式,所以如果你不小心你可能会得到很多垃圾回收。例如:

> (let ([in (open-input-string "#f (hello world)")])
    (values (read in) (read in)))
#f
'(hello world)

您可能需要进行一些后期处理,以确保您获得的是您所期望的。这也不一定会消耗所有输入,所以如果重要的是数字之后没有其他内容,你也需要单独检查它。

选项2:使用正则表达式

正则表达式是处理这种简单情况的一种非常简单的方法。在此示例中,正则表达式文字#px"^(\\d+) (\\d+)$"是表达您在问题中提到的模式的简单方法。您可以使用它来提取字符串的数字部分:

> (regexp-match #px"^(\\d+) (\\d+)$" "1 2")
'("1 2" "1" "2")

您可以将其与string->number结合使用以获取数字:

> (let ([matches (regexp-match #px"^(\\d+) (\\d+)$" "1 2")])
    (values (string->number (second matches))
            (string->number (third matches))))
1
2

这样做的好处是可以确保输入精确匹配,并且安全,快速,简单。但是,一个缺点是,如果解析失败,它将无法提供良好的错误消息,regexp-match将只生成#f

选项3:使用解析器组合器库

Racket有许多用于解析的库。这些可以扩展到解析两个数字更复杂的东西,但它们也适用于简单的情况。我将使用megaparsack显示一个示例,因为它是我的库,我喜欢它。

您可以使用megaparsack编写解析器来解析由空格分隔的两个整数:

(require data/applicative
         data/monad
         megaparsack
         megaparsack/text)

(define 2-integers/p
  (do [x <- integer/p]
      (char/p #\space)
      [y <- integer/p]
      (pure (cons x y))))

这个解析器显然比正则表达式更复杂,但它也做得更多,并且它更具可扩展性和可组合性。您可以使用此解析器来获取所需的数字:

> (parse-result! (parse-string 2-integers/p "1 2"))
'(1 . 2)

但是,与正则表达式不同,它将在解析失败时自动提供良好的错误消息:

> (parse-result! (parse-string 2-integers/p "1 "))
string:1:1: parse error
  unexpected: end of input
  expected: integer