看你的問題,我首先創建包含您的示例文本,分析器,並runTests呼叫的小腳本:
import pyparsing as pp
tests = """\
command(grep -o '(' file.txt)
command(ls -1)
"""
cmd = "command(" + pp.OneOrMore(pp.Word(pp.printables)) + ")"
cmd.runTests(tests)
正如你所說,自終止失敗「)」得到inncluded在OneOrMore
reptetition:(runTests
在這裏有用,因爲它要麼顯示分析結果,或擺了個標記,語法分析器誤入歧途)
command(grep -o '(' file.txt)
^
FAIL: Expected ")" (at char 29), (line:1, col:30)
command(ls -1)
^
FAIL: Expected ")" (at char 14), (line:1, col:15)
發生這種情況是因爲pyparsing純粹是從左到右,沒有隱含的前瞻。
最簡單直接的解決方法是從一套printables的是你的話可製成排除「)」:
cmd = "command(" + pp.OneOrMore(pp.Word(pp.printables, excludeChars=")")) + ")"
這一點讓成功的輸出:
command(grep -o '(' file.txt)
['command(', 'grep', '-o', "'('", 'file.txt', ')']
command(ls -1)
['command(', 'ls', '-1', ')']
但如果我一個不同的測試字符串添加到您的測試:
command(grep -o ')' file.txt)
的')'
是錯誤的對於關閉右括號:
command(grep -o ')' file.txt)
^
FAIL: Expected end of text (at char 18), (line:1, col:19)
通常包括的「讀,直到X」多種pyparsing表達式時,我們需要確保引號內的X不被誤解爲實際X.要做到這一點
一種方式是通過尋找引號的字符串前匹配打印的話搶先比賽:
cmd = "command(" + pp.OneOrMore(pp.quotedString |
pp.Word(pp.printables, excludeChars=")")) + ")"
現在我們的報價右括號被正確地跨過作爲引用字符串:
command(grep -o ')' file.txt)
['command(', 'grep', '-o', "')'", 'file.txt', ')']
但仍有許多可能的極端情況,可能絆倒這個解析器,因此它可能是簡單的使用pyparsing SkipTo
表達:
cmd = "command(" + pp.SkipTo(")", ignore=pp.quotedString) + ")"
其運行測試爲:
command(grep -o '(' file.txt)
['command(', "grep -o '(' file.txt", ')']
command(ls -1)
['command(', 'ls -1', ')']
command(grep -o ')' file.txt)
['command(', "grep -o ')' file.txt", ')']
請注意,我們還必須明確地告訴SkipTo
步驟在任何「)」字,可能是帶引號的字符串內。另外,我們的命令參數的主體現在作爲單個字符串返回。
如果您的命令主體本身可能包含括號內的值,那麼我們仍然會對它們進行查詢。看看這個測試:
command(grep -x '|'.join(['(', ')']) file.txt)
runTests再次向我們表明,我們已經被誤導「)」,我們不想與結束:
command(grep -x '|'.join(['(', ')']) file.txt)
^
FAIL: Expected end of text (at char 37), (line:1, col:38)
您可以添加一個超前的在「)」告訴SkipTo只匹配「)」這是正確的字符串結束前:
cmd = "command(" + pp.SkipTo(")" + pp.FollowedBy(pp.StringEnd()),
ignore=pp.quotedString) + ")"
但與此解析器,我們實際上已經恢復了,你可以用繩子做的一樣好索引,分割和剝離方法消耗臭氧層物質。
最後一個版本,向您展示使用pyparsing的nestedExpr
,這將幫助你在你的參數列表內嵌套的括號的情況:
cmd = "command" + pp.originalTextFor(pp.nestedExpr())
通常情況下,nestedExpr
將返回解析內容的嵌套列表字符串列表,但通過用originalTextFor
包裝它,我們得到原始值。還要注意,我們刪除了「(」從開「命令(」,因爲nestedExpr
將用它來解析其開括號,與這些結果:
command(grep -o '(' file.txt)
['command', "(grep -o '(' file.txt)"]
command(ls -1)
['command', '(ls -1)']
command(grep -o ')' file.txt)
['command', "(grep -o ')' file.txt)"]
command(grep -x '|'.join(['(', ')']) file.txt)
['command', "(grep -x '|'.join(['(', ')']) file.txt)"]
最終,該辦法你把和解析器的複雜性你需要的將取決於你的解析器的目標,但是這些例子應該給你一些關於如何從這裏擴展的想法。