gpt4 book ai didi

sml - 如何在 SML 中将 String 解析为 (int * int) 元组?

转载 作者:行者123 更新时间:2023-12-02 07:53:03 24 4
gpt4 key购买 nike

我有一个类似于 "3,4\r\n" 的字符串,我想将它们转换为一个元组,即 (3,4)

我们如何在 SML 中实现这一目标?

我获得字符串值的原因是因为我正在读取一个返回类似字符串的文件。

最佳答案

您需要一个简单的解析器来实现这一点。库中已经提供了解析整数的适当函数 Int.scan (以及其他类型的 friend ),但你必须自己编写其余的内容。例如:

(* scanLine : (char, 's) StringCvt.reader -> (int * int, 's) StringCvt.reader *)
fun scanLine getc stream =
case Int.scan StringCvt.DEC getc stream
of NONE => NONE
| SOME (x1, stream') =>
case getc stream'
of NONE => NONE
| SOME (c1, stream'') =>
if c1 <> #"," then NONE else
case Int.scan StringCvt.DEC getc stream''
of NONE => NONE
| SOME (x2, stream''') =>
case getc stream'''
of NONE => NONE
| SOME (c2, stream'''') =>
if c2 <> #"\n" then NONE else
SOME ((x1, x2), stream'''')

然后,解析所有行:

(* scanList : ((char, 's) StringCvt.reader -> ('a, 's) StringCvt.reader) -> (char, 's)  StringCvt.reader -> ('a list, 's) StringCvt.reader *)
fun scanList scanElem getc stream =
case scanElem getc stream
of NONE => SOME ([], stream)
| SOME (x, stream') =>
case scanList scanElem getc stream'
of NONE => NONE
| SOME (xs, stream'') => SOME (x::xs, stream'')

要使用它,例如:

val test = "4,5\n2,3\n"
val result = StringCvt.scanString (scanList scanLine) test
(* val result : (int * int) list = [(4, 5), (2, 3)] *)

正如您所看到的,代码有点重复。要摆脱选项类型的所有匹配,您可以编写一些基本的解析器组合器:

(* scanCharExpect : char -> (char, 's) StringCvt.reader -> (char, 's) StringCvt.reader *)
fun scanCharExpect expect getc stream =
case getc stream
of NONE => NONE
| SOME (c, stream') =>
if c = expect then SOME (c, stream') else NONE

(* scanSeq : ((char, 's) StringCvt.reader -> ('a, 's) StringCvt.reader) * ((char, 's) StringCvt.reader -> ('b, 's) StringCvt.reader) -> (char, 's) StringCvt.reader -> ('a * 'b, 's) StringCvt.reader *)
fun scanSeq (scan1, scan2) getc stream =
case scan1 getc stream
of NONE => NONE
| SOME (x1, stream') =>
case scan2 getc stream'
of NONE => NONE
| SOME (x2, stream'') => SOME ((x1, x2), stream'')

fun scanSeqL (scan1, scan2) getc stream =
Option.map (fn ((x, _), stream) => (x, stream)) (scanSeq (scan1, scan2) getc stream)
fun scanSeqR (scan1, scan2) getc stream =
Option.map (fn ((_, x), stream) => (x, stream)) (scanSeq (scan1, scan2) getc stream)

(* scanLine : (char, 's) StringCvt.reader -> (int * int, 's) StringCvt.reader *)
fun scanLine getc stream =
scanSeq (
scanSeqL (Int.scan StringCvt.DEC, scanCharExpect #","),
scanSeqL (Int.scan StringCvt.DEC, scanCharExpect #"\n")
) getc stream

您可以沿着这些思路构建更多很酷的抽象,特别是在定义您自己的中缀运算符时。但我就这样吧。

您可能还想处理标记之间的空白。 StringCvt.skipWS库中可以轻松使用 reader,只需将其插入到正确的位置即可。

关于sml - 如何在 SML 中将 String 解析为 (int * int) 元组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14750444/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com