summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorptmcg <ptmcg@9bf210a0-9d2d-494c-87cf-cfb32e7dff7b>2016-08-13 02:27:58 +0000
committerptmcg <ptmcg@9bf210a0-9d2d-494c-87cf-cfb32e7dff7b>2016-08-13 02:27:58 +0000
commitec420e9735ecc2a2870f8d86e3e9657245e6bfeb (patch)
treeecbc2d30cc82eb8c77d2cae22674b61718ddee1a
parent2b48ff26f8e3108d3a6859c3702cd3fd38fcede5 (diff)
downloadpyparsing-ec420e9735ecc2a2870f8d86e3e9657245e6bfeb.tar.gz
Simplified merging ParseResults from expressions in an Each; also fixed class hierarchy for OneOrMore vs. ZeroOrMore, which was causing ZeroOrMore expressions to be treated as required expressions in an Each
git-svn-id: svn://svn.code.sf.net/p/pyparsing/code/trunk@416 9bf210a0-9d2d-494c-87cf-cfb32e7dff7b
-rw-r--r--src/CHANGES5
-rw-r--r--src/pyparsing.py71
-rw-r--r--src/unitTests.py44
3 files changed, 80 insertions, 40 deletions
diff --git a/src/CHANGES b/src/CHANGES
index b73b7bb..0fca15f 100644
--- a/src/CHANGES
+++ b/src/CHANGES
@@ -12,6 +12,11 @@ Version 2.1.8 -
- Fixed bug in ParserElement.inlineLiteralsUsing, causing infinite
loop with Suppress.
+- Fixed bug in Each, when merging named results from multiple
+ expressions in a ZeroOrMore or OneOrMore. Also fixed bug when
+ ZeroOrMore expressions were erroneously treated as required
+ expressions in an Each expression.
+
- Added a few more inline doc examples.
diff --git a/src/pyparsing.py b/src/pyparsing.py
index 9191426..a99140c 100644
--- a/src/pyparsing.py
+++ b/src/pyparsing.py
@@ -58,7 +58,7 @@ The pyparsing module handles some of the problems that are typically vexing when
"""
__version__ = "2.1.8"
-__versionTime__ = "12 Aug 2016 14:46 UTC"
+__versionTime__ = "13 Aug 2016 02:22 UTC"
__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>"
import string
@@ -3554,17 +3554,7 @@ class Each(ParseExpression):
loc,results = e._parse(instring,loc,doActions)
resultlist.append(results)
- finalResults = ParseResults()
- for r in resultlist:
- dups = {}
- for k in r.keys():
- if k in finalResults:
- tmp = ParseResults(finalResults[k])
- tmp += ParseResults(r[k])
- dups[k] = tmp
- finalResults += ParseResults(r)
- for k,v in dups.items():
- finalResults[k] = v
+ finalResults = sum(resultlist, ParseResults([]))
return loc, finalResults
def __str__( self ):
@@ -3717,34 +3707,9 @@ class NotAny(ParseElementEnhance):
return self.strRepr
-
-class OneOrMore(ParseElementEnhance):
- """
- Repetition of one or more of the given expression.
-
- Parameters:
- - expr - expression that must match one or more times
- - stopOn - (default=C{None}) - expression for a terminating sentinel
- (only required if the sentinel would ordinarily match the repetition
- expression)
-
- Example::
- data_word = Word(alphas)
- label = data_word + FollowedBy(':')
- attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join))
-
- text = "shape: SQUARE posn: upper left color: BLACK"
- OneOrMore(attr_expr).parseString(text).pprint() # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']]
-
- # use stopOn attribute for OneOrMore to avoid reading label string as part of the data
- attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join))
- OneOrMore(attr_expr).parseString(text).pprint() # Better -> [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'BLACK']]
-
- # could also be written as
- (attr_expr * (1,)).parseString(text).pprint()
- """
+class _MultipleMatch(ParseElementEnhance):
def __init__( self, expr, stopOn=None):
- super(OneOrMore, self).__init__(expr)
+ super(_MultipleMatch, self).__init__(expr)
ender = stopOn
if isinstance(ender, basestring):
ender = ParserElement._literalStringClass(ender)
@@ -3778,6 +3743,32 @@ class OneOrMore(ParseElementEnhance):
pass
return loc, tokens
+
+class OneOrMore(_MultipleMatch):
+ """
+ Repetition of one or more of the given expression.
+
+ Parameters:
+ - expr - expression that must match one or more times
+ - stopOn - (default=C{None}) - expression for a terminating sentinel
+ (only required if the sentinel would ordinarily match the repetition
+ expression)
+
+ Example::
+ data_word = Word(alphas)
+ label = data_word + FollowedBy(':')
+ attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join))
+
+ text = "shape: SQUARE posn: upper left color: BLACK"
+ OneOrMore(attr_expr).parseString(text).pprint() # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']]
+
+ # use stopOn attribute for OneOrMore to avoid reading label string as part of the data
+ attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join))
+ OneOrMore(attr_expr).parseString(text).pprint() # Better -> [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'BLACK']]
+
+ # could also be written as
+ (attr_expr * (1,)).parseString(text).pprint()
+ """
def __str__( self ):
if hasattr(self,"name"):
@@ -3793,7 +3784,7 @@ class OneOrMore(ParseElementEnhance):
ret.saveAsList = True
return ret
-class ZeroOrMore(OneOrMore):
+class ZeroOrMore(_MultipleMatch):
"""
Optional repetition of zero or more of the given expression.
diff --git a/src/unitTests.py b/src/unitTests.py
index 1f7964e..b80a9f4 100644
--- a/src/unitTests.py
+++ b/src/unitTests.py
@@ -2275,9 +2275,53 @@ class OptionalEachTest(ParseTestCase):
assert modifiers == "with foo=bar bing=baz using id-deadbeef"
assert not modifiers == "with foo=bar bing=baz using id-deadbeef using id-feedfeed"
+ def runTest3(self):
+ from pyparsing import Literal,Suppress,ZeroOrMore,OneOrMore
+
+ foo = Literal('foo')
+ bar = Literal('bar')
+
+ openBrace = Suppress(Literal("{"))
+ closeBrace = Suppress(Literal("}"))
+
+ exp = openBrace + (OneOrMore(foo)("foo") & ZeroOrMore(bar)("bar")) + closeBrace
+
+ tests = """\
+ {foo}
+ {bar foo bar foo bar foo}
+ """.splitlines()
+ for test in tests:
+ test = test.strip()
+ if not test:
+ continue
+ result = exp.parseString(test)
+ print(test, '->', result.asList())
+ assert result.asList() == test.strip("{}").split(), "failed to parse Each expression %r" % test
+ print(result.dump())
+
+ try:
+ result = exp.parseString("{bar}")
+ assert False, "failed to raise exception when required element is missing"
+ except ParseException as pe:
+ pass
+
+ def runTest4(self):
+ from pyparsing import pyparsing_common, ZeroOrMore, Group
+
+ expr = ((~pyparsing_common.iso8601_date + pyparsing_common.integer("id"))
+ & ZeroOrMore(Group(pyparsing_common.iso8601_date)("date*")))
+
+ expr.runTests("""
+ 1999-12-31 100 2001-01-01
+ 42
+ """)
+
+
def runTest(self):
self.runTest1()
self.runTest2()
+ self.runTest3()
+ self.runTest4()
class SumParseResultsTest(ParseTestCase):
def runTest(self):