SML 在第一个 space 上拆分字符串
SML splitting string on first space
截至目前,我正在使用 inputAll 读取整个输入文件,然后在每次出现 space 时使用 String.tokens 拆分每个单词。
val file = TextIO.openIn input
val _input = TextIO.inputAll file
val _ = TextIO.closeIn file
String.tokens Char.isSpace _input
Ex) "red blue green" 看起来像这样
["red", "blue", "green"]
但是,现在我想将其更改为仅在每行第一次出现 space 字符时拆分字符串。
Ex) "red blue green" 应该看起来像
["red", "blue green"]
我觉得我需要利用 inputAll 以外的东西来完成这个,我的主要问题是你如何做到这一点,所以它只在每行的第一个 space 处拆分。
TextIO.inputAll
没问题。在这种情况下,String.tokens
似乎不是完成这项工作的正确工具。就我个人而言,我只会编写自己的函数,使用 String.explode
和 String.implode
来转换 string
to/from char list
.
fun splitCharsFirstSpace cs =
case cs of
[] => ([], [])
| c :: cs' =>
if Char.isSpace c then ([], cs')
else let val (l, r) = splitCharsFirstSpace cs'
in (c :: l, r)
end
fun splitFirstSpace s =
let
val (l, r) = splitCharsFirstSpace (String.explode s)
in
(String.implode l, String.implode r)
end
在上下文中,您可以按如下方式使用它。
val file = TextIO.openIn input
val contents = TextIO.inputAll file
val _ = TextIO.closeIn file
val lines = String.tokens (fn c => c = #"\n") contents
val lines' = List.map splitFirstSpace lines
例如,如果您的输入文件是这样的:
red blue green
yellow orange purple pink
那么 lines'
将如下所示:
[("red", "blue green"), ("yellow", "orange purple pink")]
这是另一个使用 Substring 的函数 dropl、dropr 和 splitl 的选项
连同 TextIO.inputLine.
structure SS = Substring;
structure C = Char;
structure TIO = TextIO;
fun splitFile(arg) =
let val file = TIO.openIn arg
val line = TIO.inputLine file;
fun trimWs ss = (SS.dropl (C.isSpace) (SS.dropr (C.isSpace) ss));
fun splitLine(SOME str) acc =
let val (l, r) = SS.splitl (not o C.isSpace) (SS.full str);
val (l, r) = (trimWs l, trimWs r);
in if SS.size l + SS.size r = 0
then splitLine (TIO.inputLine file) acc
else (SS.string l, SS.string r)::splitLine (TIO.inputLine file) acc
end
| splitLine (NONE) acc = acc;
val result = splitLine line [];
val _ = TextIO.closeIn file
in result end
截至目前,我正在使用 inputAll 读取整个输入文件,然后在每次出现 space 时使用 String.tokens 拆分每个单词。
val file = TextIO.openIn input
val _input = TextIO.inputAll file
val _ = TextIO.closeIn file
String.tokens Char.isSpace _input
Ex) "red blue green" 看起来像这样
["red", "blue", "green"]
但是,现在我想将其更改为仅在每行第一次出现 space 字符时拆分字符串。
Ex) "red blue green" 应该看起来像
["red", "blue green"]
我觉得我需要利用 inputAll 以外的东西来完成这个,我的主要问题是你如何做到这一点,所以它只在每行的第一个 space 处拆分。
TextIO.inputAll
没问题。在这种情况下,String.tokens
似乎不是完成这项工作的正确工具。就我个人而言,我只会编写自己的函数,使用 String.explode
和 String.implode
来转换 string
to/from char list
.
fun splitCharsFirstSpace cs =
case cs of
[] => ([], [])
| c :: cs' =>
if Char.isSpace c then ([], cs')
else let val (l, r) = splitCharsFirstSpace cs'
in (c :: l, r)
end
fun splitFirstSpace s =
let
val (l, r) = splitCharsFirstSpace (String.explode s)
in
(String.implode l, String.implode r)
end
在上下文中,您可以按如下方式使用它。
val file = TextIO.openIn input
val contents = TextIO.inputAll file
val _ = TextIO.closeIn file
val lines = String.tokens (fn c => c = #"\n") contents
val lines' = List.map splitFirstSpace lines
例如,如果您的输入文件是这样的:
red blue green
yellow orange purple pink
那么 lines'
将如下所示:
[("red", "blue green"), ("yellow", "orange purple pink")]
这是另一个使用 Substring 的函数 dropl、dropr 和 splitl 的选项 连同 TextIO.inputLine.
structure SS = Substring;
structure C = Char;
structure TIO = TextIO;
fun splitFile(arg) =
let val file = TIO.openIn arg
val line = TIO.inputLine file;
fun trimWs ss = (SS.dropl (C.isSpace) (SS.dropr (C.isSpace) ss));
fun splitLine(SOME str) acc =
let val (l, r) = SS.splitl (not o C.isSpace) (SS.full str);
val (l, r) = (trimWs l, trimWs r);
in if SS.size l + SS.size r = 0
then splitLine (TIO.inputLine file) acc
else (SS.string l, SS.string r)::splitLine (TIO.inputLine file) acc
end
| splitLine (NONE) acc = acc;
val result = splitLine line [];
val _ = TextIO.closeIn file
in result end