diff --git a/CHANGELOG.md b/CHANGELOG.md index ec3ece5..7865efe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +v0.13 +================== + +* Add `groupFirstCapture`, `groupLastCapture`, and + `group(1): seq[string]` (thaks to @xmonader) +* Add Nim 1.0.0 to CI +* Drop Nim 0.18 support +* Fix nested captures with repetition range; issue #46 +* Fix Nim `sets` warnings + v0.12 ================== diff --git a/docs/index.html b/docs/index.html index 507a59a..6dcc934 100644 --- a/docs/index.html +++ b/docs/index.html @@ -99,6 +99,23 @@ width: 80%; } +/* + * Some custom formatting for input forms. + * This also fixes input form colors on Firefox with a dark system theme on Linux. + */ +input { + -moz-appearance: none; + color: #333; + background-color: #f8f8f8; + border: 1px solid #aaa; + font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif; + font-size: 0.9em; + padding: 6px; +} +input:focus { + border: 1px solid #1fa0eb; + box-shadow: 0 0 2px #1fa0eb; +} /* Docgen styles */ /* Links */ @@ -825,12 +842,12 @@
Regex = object states: seq[Node] groupsCount: int16 - namedGroups: Table[string, int16] + namedGroups: OrderedTable[string, int16]
RegexMatch = object captures: seq[Slice[int]] groups: seq[Slice[int]] - namedGroups: Table[string, int16] + namedGroups: OrderedTable[string, int16] boundaries*: Slice[int]
proc groupsCount(m: RegexMatch): int {...}{.raises: [], tags: [].}
block: - var m: RegexMatch - doAssert "ab".match(re"(a)(b)", m) - doAssert m.groupsCount == 2 -block: - var m: RegexMatch - doAssert "ab".match(re"((ab))", m) - doAssert m.groupsCount == 2+return the number of capturing groups +
Examples:
+var m: RegexMatch +doAssert "ab".match(re"(a)(b)", m) +doAssert m.groupsCount == 2+ +
proc groupNames(m: RegexMatch): seq[string] {...}{.raises: [], tags: [].}
Examples:
+let text = "hello world" +var m: RegexMatch +doAssert text.match(re"(?P<greet>hello) (?P<who>world)", m) +doAssert m.groupNames() == @["greet", "who"]+ +
proc group(m: RegexMatch; groupName: string; text: string): seq[string] {...}{. + raises: [KeyError], tags: [].}
Examples:
+let text = "hello beautiful world" +var m: RegexMatch +doAssert text.match(re"(?P<greet>hello) (?:(?P<who>[^\s]+)\s?)+", m) +doAssert m.group("greet", text) == @["hello"] +doAssert m.group("who", text) == @["beautiful", "world"]+ +
proc groupFirstCapture(m: RegexMatch; groupName: string; text: string): string {...}{. + raises: [KeyError], tags: [].}
Examples:
+let text = "hello beautiful world" +var m: RegexMatch +doAssert text.match(re"(?P<greet>hello) (?:(?P<who>[^\s]+)\s?)+", m) +doAssert m.groupFirstCapture("greet", text) == "hello" +doAssert m.groupFirstCapture("who", text) == "beautiful"+ +
proc groupLastCapture(m: RegexMatch; groupName: string; text: string): string {...}{. + raises: [KeyError], tags: [].}
Examples:
+let text = "hello beautiful world" +var m: RegexMatch +doAssert text.match(re"(?P<greet>hello) (?:(?P<who>[^\s]+)\s?)+", m) +doAssert m.groupLastCapture("greet", text) == "hello" +doAssert m.groupLastCapture("who", text) == "world"
var m: RegexMatch -doAssert "abcd".match(re"abcd", m) -doAssert(not "abcd".match(re"abc", m))+return a match if the whole string matches the regular expression. This is similar to find(text, re"^regex$") but has better performance +
Examples:
+var m: RegexMatch +doAssert "abcd".match(re"abcd", m) +doAssert(not "abcd".match(re"abc", m))
proc contains(s: string; pattern: Regex): bool {...}{.raises: [], tags: [].}
doAssert(re"bc" in "abcd") -doAssert(re"(23)+" in "23232") -doAssert(re"^(23)+$" notin "23232")+search for the pattern anywhere in the string. It returns as soon as there is a match, even when the expression has repetitions. Use re"^regex$" to match the whole string instead of searching +
Examples:
+doAssert(re"bc" in "abcd") +doAssert(re"(23)+" in "23232") +doAssert(re"^(23)+$" notin "23232")
var m: RegexMatch -doAssert "abcd".find(re"bc", m) -doAssert(not "abcd".find(re"de", m)) -doAssert "2222".find(re"(22)*", m) and - m.group(0) == @[0 .. 1, 2 .. 3]+search through the string looking for the first location where there is a match +
Examples:
+var m: RegexMatch +doAssert "abcd".find(re"bc", m) +doAssert(not "abcd".find(re"de", m)) +doAssert("2222".find(re"(22)*", m) and m.group(0) == @[0 .. 1, 2 .. 3])
proc findAndCaptureAll(s: string; pattern: Regex): seq[string] {...}{.raises: [], tags: [].}
let - expected = @["1", "2", "3", "4", "5"] - res = findAndCaptureAll("a1b2c3d4e5", re"\d") -doAssert(res == expected)+search through the string and return a seq with captures. +
Examples:
+let + captured = findAndCaptureAll("a1b2c3d4e5", re"\d") + expected = @["1", "2", "3", "4", "5"] +doAssert captured == expected
proc split(s: string; sep: Regex): seq[string] {...}{.raises: [], tags: [].}
doAssert(split("11a22Ϊ33Ⓐ44弢55", re"\d+") == - @["", "a", "Ϊ", "Ⓐ", "弢", ""])+return not matched substrings +
Examples:
+let + parts = split("11a22Ϊ33Ⓐ44弢55", re"\d+") + expected = @["", "a", "Ϊ", "Ⓐ", "弢", ""] +doAssert parts == expected
proc splitIncl(s: string; sep: Regex): seq[string] {...}{.raises: [], tags: [].}
doAssert splitIncl("a,b", re"(,)") == - @["a", ",", "b"]+return not matched substrings, including captured groups +
Examples:
+let + parts = splitIncl("a,b", re"(,)") + expected = @["a", ",", "b"] +doAssert parts == expected
proc startsWith(s: string; pattern: Regex; start = 0): bool {...}{.raises: [], tags: [].}
doAssert("abc".startsWith(re"\w")) -doAssert(not "abc".startsWith(re"\d"))+return whether the string starts with the pattern or not +
Examples:
+doAssert "abc".startsWith(re"\w") +doAssert(not "abc".startsWith(re"\d"))
proc endsWith(s: string; pattern: Regex): bool {...}{.raises: [], tags: [].}
doAssert("abc".endsWith(re"\w")) -doAssert(not "abc".endsWith(re"\d"))+return whether the string ends with the pattern or not +
Examples:
+doAssert "abc".endsWith(re"\w") +doAssert(not "abc".endsWith(re"\d"))
Replace matched substrings.
Matched groups can be accessed with $N notation, where N is the group's index, starting at 1 (1-indexed). $$ means literal $.
If limit is given, at most limit replacements are done. limit of 0 means there is no limit
-doAssert("aaa".replace(re"a", "b", 1) == "baa") -doAssert("abc".replace(re"(a(b)c)", "m($1) m($2)") == - "m(abc) m(b)") -doAssert("Nim is awesome!".replace(re"(\w\B)", "$1_") == - "N_i_m i_s a_w_e_s_o_m_e!")+ +
Examples:
+doAssert "aaa".replace(re"a", "b", 1) == "baa" +doAssert("abc".replace(re"(a(b)c)", "m($1) m($2)") == "m(abc) m(b)") +doAssert("Nim is awesome!".replace(re"(\w\B)", "$1_") == + "N_i_m i_s a_w_e_s_o_m_e!")@@ -1146,35 +1242,40 @@
Replace matched substrings.
If limit is given, at most limit replacements are done. limit of 0 means there is no limit
-proc removeEvenWords(m: RegexMatch, s: string): string = - result = "" - if m.group(1).len mod 2 != 0: - result = s[m.group(0)[0]] + +Examples:
+proc removeEvenWords(m: RegexMatch; s: string): string = + result = "" + if m.group(1).len mod 2 != 0: + result = s[m.group(0)[0]] let - text = "Es macht Spaß, alle geraden Wörter zu entfernen!" - expected = "macht , geraden entfernen!" -doAssert(text.replace(re"((\w)+\s*)", removeEvenWords) == expected)+ text = "Es macht Spaß, alle geraden Wörter zu entfernen!" + expected = "macht , geraden entfernen!" +doAssert text.replace(re"((\w)+\s*)", removeEvenWords) == expected
proc toPattern(s: string): Regex {...}{.raises: [RegexError], tags: [].}
# compiled at run-time -let patternA = toPattern(r"aa?") -# compiled at compile-time -const patternB = toPattern(r"aa?")+Parse and compile a regular expression. Deprecated: use directly re instead which works both at RT and CT. +
Examples:
+let patternRt = toPattern(r"aa?") +const + patternCt = toPattern(r"aa?")
proc isInitialized(re: Regex): bool {...}{.raises: [], tags: [].}
var re: Regex -assert(not re.isInitialized) -re = re"foo" -assert re.isInitialized+Check whether the regex has been initialized +
Examples:
+var re: Regex +doAssert(not re.isInitialized) +re = re"foo" +doAssert re.isInitialized
iterator group(m: RegexMatch; i: int): Slice[int] {...}{.raises: [], tags: [].}
let - expected = ["a", "b", "c"] - text = "abc" -var m: RegexMatch -doAssert text.match(re"(\w)+", m) -var i = 0 -for bounds in m.group(0): - doAssert(expected[i] == text[bounds]) - inc i+return slices for a given group. Slices of start > end are empty matches (i.e.: re"(\d?)") and they are included same as in PCRE. +
Examples:
+let text = "abc" +var m: RegexMatch +doAssert text.match(re"(\w)+", m) +var captures = newSeq[string]() +for bounds in m.group(0): + captures.add(text[bounds]) +doAssert captures == @["a", "b", "c"]
iterator group(m: RegexMatch; s: string): Slice[int] {...}{.raises: [KeyError], tags: [].}
let - expected = ["a", "b", "c"] - text = "abc" -var m: RegexMatch -doAssert text.match(re"(?P<foo>\w)+", m) -var i = 0 -for bounds in m.group("foo"): - doAssert(expected[i] == text[bounds]) - inc i+return slices for a given named group +
Examples:
+let text = "abc" +var m: RegexMatch +doAssert text.match(re"(?P<foo>\w)+", m) +var captures = newSeq[string]() +for bounds in m.group("foo"): + captures.add(text[bounds]) +doAssert captures == @["a", "b", "c"]
var i = 0 -let - expected = [1 .. 2, 4 .. 5] - text = "abcabc" -for m in findAll(text, re"bc"): - doAssert text[m.boundaries] == "bc" - doAssert m.boundaries == expected[i] +search through the string and return each match. Empty matches (start > end) are included +Examples:
+var + expected = [1 .. 2, 4 .. 5] + text = "abcabc" + i = 0 +for m in findAll(text, re"bc"): + doAssert text[m.boundaries] == "bc" + doAssert m.boundaries == expected[i] inc i
iterator split(s: string; sep: Regex): string {...}{.inline, raises: [], tags: [].}
var i = 0 -let expected = ["", "a", "Ϊ", "Ⓐ", "弢", ""] -for s in split("11a22Ϊ33Ⓐ44弢55", re"\d+"): - doAssert(s == expected[i]) +return not matched substrings +Examples:
+var + expected = ["", "a", "Ϊ", "Ⓐ", "弢", ""] + i = 0 +for s in split("11a22Ϊ33Ⓐ44弢55", re"\d+"): + doAssert(s == expected[i]) inc i