扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
作者:IBM.COM 来源:IBM.COM 2007年9月15日
关键字: 软件
DParser 可以显示调试信息的选项,这是我所喜欢的它的一个方面。观察这些信息并不是直观地创建正确语法所必需的,但是至少可以通过它洞察当处理特定的短语时解析器所采取的动作。例如:
清单 8. 展示对不确定结果的追踪
#------- Showing a trace of speculative productions
$ echo -n "alex alice benny carl dave" | ./abc2.py --debug
d_words ???:
d_A ???: alex
d_word ???: alex
d_words ???:
d_phrase ???: alex
d_words ???: alex
d_A ???: alice
d_word ???: alice
d_words ???:
d_words ???: alice
d_phrase ???: alex alice
d_phrase ???: alex alice
d_words ???: alex alice
d_word ???: benny
d_AB ???: alice benny
d_words ???: benny
d_words ???: alice benny
d_words ???:
d_phrase ???: alex alice benny
d_phrase ???: alex alice benny
d_phrase ???: alex alice benny
d_words ???: alex alice benny
d_word: alex
d_words: alex
d_A: alice
d_AB: alice benny
d_ABC ???: alice benny carl
d_words ???:
d_phrase ???: alex alice benny carl
d_ABC: alice benny carl
d_word ???: dave
d_words ???: dave
d_phrase ???: alex alice benny carl dave
d_word: dave
d_words: dave
d_phrase: alex alice benny carl dave
Head: alex
ABC: alice benny carl
Tail: dave
后面跟有问号的结果是推测性的尝试;那些后面其实没有最终的结果。与此相关, DParser 让您有能力当结果成为推测的或者是最终解析时采取不同的动作。默认情况下,函数体中的动作只作用于最终解析。不过,您可以向结果指定两个额外参数中的一个来处理推测性解析。(还有很多本文中没有讨论的选项参数。)
清单 9. 推测性解析过程中的动作
def d_prod1(t, spec_only):
'prod1 : this that+ other?'
print "Speculative parse of prod1"
def d_prod2(t, spec):
'prod2: spam* eggs toast'
if spec:
print "Speculative parse of prod2"
else:
print "Final parse of prod2"
当然,通过指定 dparser.Parser.parse() 的 print_debug_info 参数,我的推测性解析所显示的所有信息也都显示出来(以稍微不同的格式)。不过您也可以决定采取其他动作 —— 比如触发外部事件。
深入探讨优先级
我承认,前面 ABC 结果所使用的指定优先级有些不太正统。但是假如是简单含糊短语,则微调结束优先级是一个非常好的工具。让我来给出另一个关于简单含糊短语的语法:
清单 10. 逐项的二义性语法,ibm.py
def d_phrase(t, s):
'phrase : word ( vowel | caps | threeletter ) word'
print "Head:", ''.join(s[0])
print t[1][0]+":", ''.join(s[1])
print "Tail:", ''.join(s[2])
def d_word(t): 'word : "[A-Za-z]+" '
def d_vowel(t):
'vowel : "[AEIOUaeiou][A-Za-z]*"'
return 'VOWEL'
def d_caps(t):
'caps : "[A-Z]+"'
return 'CAPS'
def d_threeletter(t):
'threeletter : "[A-Za-z][A-Za-z][A-Za-z]"'
return '3LETT'
#-- Parse STDIN
from dparser import Parser
from sys import stdin
Parser().parse(stdin.read())
vowel、caps 和 threeletter 的结果不需要是确切的;它们全部都可以获取彼此有重叠的单词集合。例如:
清单 11. 当 DParser 得体地检测到含糊短语
$ echo -n "Read IBM developerWorks" | ./ibm.py
Traceback (most recent call last): [...]
dparser.AmbiguityException: [...]
当然,您可能幸运地使用了特定的短语:
清单 12. 幸运地避免了含糊短语的解析
$ echo -n "Read GNOSIS website" | ./ibm.py
Head: Read
CAPS: GNOSIS
Tail: website
不要满足于祈祷好运,让我们来显式地指定结果之间的优先级:
清单 13. 判定含糊的条件,ibm2.py
def d_vowel(t):
'vowel : "[AEIOUaeiou][A-Za-z]*" $term 3'
return 'VOWEL'
def d_caps(t):
'caps : "[A-Z]+" $term 2'
return 'CAPS'
def d_threeletter(t):
'threeletter : "[A-Za-z][A-Za-z][A-Za-z]" $term 1'
return '3LETT'
现在,每一个短语都将以特定的顺序识别出中间单词的类型(当然只是可能的那些):
清单 14. 无歧义的解析结果
$ echo -n "Read IBM developerWorks" | ./ibm2.py
Head: Read
VOWEL: IBM
Tail: developerWorks
$ echo -n "Read XYZ journal" | ./ibm2.py
Head: Read
CAPS: XYZ
Tail: journal
做出决定
尽管得到了一些读者的建议,我还是不太看重 DParser。它有很多可以作用于结果的强大的开关和选项,我还没有讨论到 —— 比如指定关联性。大体上,DParser 语言非常健壮,我非常怀疑用于 Python 的 DParser 是否会比纯粹的 Python 解析器运行速度快得非常多。
无论如何,我仍然不能对函数文档字符串风格的解析器具有太多热情。显然,关于这一点,很多优秀的 Python 程序员不会赞同我。此外我还发现一些解析结果有些令人不解:为什么调试模式下可以成功,而标准模式下却不能成功?含糊问题确切是什么时候发生的?使用任何解析工具开发语法都会有类似的意外,但是我发现 DParser 不知何故尤其出乎意料;例如 SimpleParse,就不会让我那么感到惊讶。可能,如果我了解了底层算法的更多复杂细节,它将会更具意义;不过,就我相对浅薄的学识而言,我可能与 95% 以上的读者差不多。有人比我更加熟悉解析;但是实际上大部分程序员懂得更少。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者