Change RegexMatch from ref to Option

Also associated changes to tests and code
This commit is contained in:
Flaviu Tamas
2015-01-28 20:33:33 -05:00
parent 43127455cb
commit a1110ebb14
5 changed files with 20 additions and 23 deletions

View File

@@ -18,7 +18,7 @@ type
captureNameToId: Table[string, int]
RegexMatch* = ref object
RegexMatch* = object
## Is returned upon a match.
pattern*: Regex ## The regex doing the matching.
## Not nil.
@@ -286,10 +286,8 @@ proc re*(pattern: string, options = ""): Regex = initRegex(pattern, options)
# }}}
# Operations {{{
proc matchImpl(str: string, pattern: Regex, start, endpos: int, flags: int): RegexMatch =
new(result)
result.pattern = pattern
result.str = str
proc matchImpl(str: string, pattern: Regex, start, endpos: int, flags: int): Option[RegexMatch] =
var result = RegexMatch(pattern : pattern, str : str)
# See PCRE man pages.
# 2x capture count to make room for start-end pairs
# 1x capture count as slack space for PCRE
@@ -309,13 +307,13 @@ proc matchImpl(str: string, pattern: Regex, start, endpos: int, flags: int): Reg
cast[ptr cint](addr result.pcreMatchBounds[0]),
cint(vecsize))
if execRet >= 0:
return result
return Some(result)
elif execRet == pcre.ERROR_NOMATCH:
return nil
return None[RegexMatch]()
else:
raise newException(AssertionError, "Internal error: errno " & $execRet)
proc match*(str: string, pattern: Regex, start = 0, endpos = -1): RegexMatch =
proc match*(str: string, pattern: Regex, start = 0, endpos = -1): Option[RegexMatch] =
return str.matchImpl(pattern, start, endpos, pcre.ANCHORED)
iterator findIter*(str: string, pattern: Regex, start = 0, endpos = -1): RegexMatch =
@@ -325,19 +323,18 @@ iterator findIter*(str: string, pattern: Regex, start = 0, endpos = -1): RegexMa
let endpos = if endpos == -1: str.len else: endpos
var offset = start
var previousMatch: RegexMatch
var match: Option[RegexMatch]
while true:
var flags = 0
if previousMatch != nil and
previousMatch.matchBounds.a == previousMatch.matchBounds.b:
if match and
match.get.matchBounds.a == match.get.matchBounds.b:
# 0-len match
flags = pcre.NOTEMPTY_ATSTART or pcre.ANCHORED
let currentMatch = str.matchImpl(pattern, offset, endpos, flags)
previousMatch = currentMatch
match = str.matchImpl(pattern, offset, endpos, flags)
if currentMatch == nil:
if match.isNone:
# either the end of the input or the string
# cannot be split here
offset += 1
@@ -351,15 +348,15 @@ iterator findIter*(str: string, pattern: Regex, start = 0, endpos = -1): RegexMa
offset += str.runeLenAt(offset)
assert(offset <= endpos)
else:
offset = currentMatch.matchBounds.b
offset = match.get.matchBounds.b
yield currentMatch
yield match.get
if offset >= endpos:
# do while
break
proc find*(str: string, pattern: Regex, start = 0, endpos = -1): RegexMatch =
proc find*(str: string, pattern: Regex, start = 0, endpos = -1): Option[RegexMatch] =
## Returns a `RegexMatch` if there is a match between `start` and `endpos`, otherwise
## it returns nil.
##

View File

@@ -1,4 +1,4 @@
import unittest
import unittest, optional_t.nonstrict
include nre
suite "captures":

View File

@@ -1,4 +1,4 @@
import unittest, sequtils, nre
import unittest, sequtils, nre, optional_t.nonstrict
suite "find":
test "find text":

View File

@@ -1,9 +1,9 @@
include nre, unittest
include nre, unittest, optional_t.nonstrict
suite "match":
test "upper bound must be exclusive":
check("abc".match(re"abc", endpos = 0) == nil)
check("abc".match(re"abc", endpos = 3) != nil)
check("abc".match(re"abc", endpos = 0) == None[RegexMatch]())
check("abc".match(re"abc", endpos = 3) != None[RegexMatch]())
test "match examples":
check("abc".match(re"(\w)").captures[0] == "a")

View File

@@ -1,4 +1,4 @@
import unittest, nre
import unittest, nre, optional_t.nonstrict
suite "Misc tests":
test "unicode":