diff options
-rw-r--r-- | lib/pure/strscans.nim | 7 | ||||
-rw-r--r-- | tests/stdlib/tstrscans.nim | 86 |
2 files changed, 90 insertions, 3 deletions
diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index 77763ff43..c1c535e55 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -129,7 +129,7 @@ to use prefix instead of postfix operators. ``+E`` One or more ``?E`` Zero or One ``E{n,m}`` From ``n`` up to ``m`` times ``E`` -``~Ε`` Not predicate +``~E`` Not predicate ``a ^* b`` Shortcut for ``?(a *(b a))``. Usually used for separators. ``a ^* b`` Shortcut for ``?(a +(b a))``. Usually used for separators. ``'a'`` Matches a single character @@ -456,10 +456,11 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b template atom*(input: string; idx: int; c: char): bool = ## Used in scanp for the matching of atoms (usually chars). - idx < input.len and input[idx] == c + ## EOF is matched as ``'\0'``. + (idx < input.len and input[idx] == c) or (idx == input.len and c == '\0') template atom*(input: string; idx: int; s: set[char]): bool = - idx < input.len and input[idx] in s + (idx < input.len and input[idx] in s) or (idx == input.len and '\0' in s) template hasNxt*(input: string; idx: int): bool = idx < input.len diff --git a/tests/stdlib/tstrscans.nim b/tests/stdlib/tstrscans.nim new file mode 100644 index 000000000..08fc14e45 --- /dev/null +++ b/tests/stdlib/tstrscans.nim @@ -0,0 +1,86 @@ +discard """ + output: "" +""" + +import strscans + +block ParsePasswd: + proc parsePasswd(content: string): seq[string] = + result = @[] + var idx = 0 + while true: + var entry = "" + if scanp(content, idx, +(~{'\L', '\0'} -> entry.add($_)), '\L'): + result.add entry + else: + break + + const etc_passwd = """root:x:0:0:root:/root:/bin/bash +daemon:x:1:1:daemon:/usr/sbin:/bin/sh +bin:x:2:2:bin:/bin:/bin/sh +sys:x:3:3:sys:/dev:/bin/sh +nobody:x:65534:65534:nobody:/nonexistent:/bin/sh +messagebus:x:103:107::/var/run/dbus:/bin/false +""" + + const parsed_etc_passwd = @[ + "root:x:0:0:root:/root:/bin/bash", + "daemon:x:1:1:daemon:/usr/sbin:/bin/sh", + "bin:x:2:2:bin:/bin:/bin/sh", + "sys:x:3:3:sys:/dev:/bin/sh", + "nobody:x:65534:65534:nobody:/nonexistent:/bin/sh", + "messagebus:x:103:107::/var/run/dbus:/bin/false", + ] + doAssert etc_passwd.parsePasswd == parsed_etc_passwd + +block LastNot: + var idx : int + + idx = 0 + doAssert scanp("foo", idx, 'f', 'o', ~'a') + + idx = 0 + doAssert scanp("foo", idx, 'f', 'o', ~'o') == false + + idx = 0 + doAssert scanp("foox", idx, 'f', 'o', ~'o') == false + + idx = 0 + doAssert scanp("foox", idx, 'f', 'o', ~'a') + +block LastOptional: + var idx = 0 + doAssert scanp("foo", idx, 'f', 'o', 'o', ?'o') + +block Tuple: + var idx = 0 + doAssert scanp("foo", idx, ('f', 'o', 'o')) + +block NotWithOptional: + var idx : int + + idx = 0 + doAssert scanp("bc", idx, ~(?'b', 'c')) == false + + idx = 0 + doAssert scanp("c", idx, ~(?'b', 'c')) == false + + idx = 0 + doAssert scanp("b", idx, ~(?'b', 'c')) + +block NotEmpty: + var idx = 0 + doAssert scanp("", idx, ~()) == false + +block EmptyTuple: + var idx = 0 + doAssert scanp("ab", idx, 'a', (), 'b') + +block Arrow: + let text = "foo;bar;baz;" + var idx = 0 + var res = "" + doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';') + doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';') + doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';') + doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';') == false |