问题
As of right now I am reading in an entire input file using inputAll and then using String.tokens to split each word at every occurrence of space.
val file = TextIO.openIn input
val _input = TextIO.inputAll file
val _ = TextIO.closeIn file
String.tokens Char.isSpace _input
Ex) "red blue green" would look like this
["red", "blue", "green"]
However, now I would like to change it to only split the string at the first occurrence of a space char on each line.
Ex) "red blue green" should look like
["red", "blue green"]
I have a feeling I will need to utilize something other than inputAll to accomplish this, and my main question is how do you make it so it only splits at the first space of each line.
回答1:
TextIO.inputAll
is fine. In this case it seems that String.tokens
is not the right tool for the job. Personally I would just write my own function, using String.explode
and String.implode
to convert a 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
In context, you could use this as follows.
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
For example, if your input file was this:
red blue green
yellow orange purple pink
then lines'
would look like this:
[("red", "blue green"), ("yellow", "orange purple pink")]
回答2:
Here is another option using the functions dropl, dropr, and splitl of Substring along with 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
来源:https://stackoverflow.com/questions/43289155/sml-splitting-string-on-first-space