Parsing 如何创建配方/成分分析器

Parsing 如何创建配方/成分分析器,parsing,Parsing,给出一行,例如 一磅牛肉 我想提取成分。最初我只对成分名称感兴趣 我看了Ruby著名的时间分析器,喜欢它使用正则表达式 def self.scan_for_month_names(token) scanner = {/^jan\.?(uary)?$/ => :january, /^feb\.?(ruary)?$/ => :february, /^mar\.?(ch)?$/ => :march, /^apr\.?

给出一行,例如

一磅牛肉

我想提取成分。最初我只对成分名称感兴趣

我看了Ruby著名的时间分析器,喜欢它使用正则表达式

 def self.scan_for_month_names(token)
scanner = {/^jan\.?(uary)?$/ => :january,
           /^feb\.?(ruary)?$/ => :february,
           /^mar\.?(ch)?$/ => :march,
           /^apr\.?(il)?$/ => :april,
           /^may$/ => :may,
           /^jun\.?e?$/ => :june,
           /^jul\.?y?$/ => :july,
           /^aug\.?(ust)?$/ => :august,
           /^sep\.?(tember)?$/ => :september,
           /^oct\.?(ober)?$/ => :october,
           /^nov\.?(ember)?$/ => :november,
           /^dec\.?(ember)?$/ => :december}
scanner.keys.each do |scanner_item|
  return Chronic::RepeaterMonthName.new(scanner[scanner_item]) if scanner_item =~ token.word
end
return nil
结束

然而在我的例子中,我可能需要为每种成分创建300多个正则表达式

我还必须考虑一些同义词,如香菜叶


我以前从未做过语法分析,但是在这里使用正则表达式仍然是最好的方法吗。我想不出任何其他合理的替代方案。

我想我应该从对每行运行一系列正则表达式检查开始,并在运行时调整解析的文本。例如(伪代码):

首先,检查指令:

/^(add|fold in|stir in|etc...)/
如果找到指令,请将其从行中删除,设置标志,然后继续:

instruction = $1
this_line = this_line.substring(instruction.length())
如果找到指令,检查是否有后续指令(如“和封面”或“和搁置”)

如果找到,将其剥离并插入配方的下一行之前

instruction = instruction.substring(0, instuction.length - $1.length - $2.length)
splice $2 into the array of lines immediately following this one
下一步,也许你要检查一个介词:

/((?in)to\s(.+)/
如果发现,您可以使用它来检查设备名称、碗、量杯等。 即使不使用它,也可以从正在解析的字符串中删除它,以改进匹配

最后,真正的工作是用剩下的文本完成的:

Check against /^(\d+\s+(?a\s)?\w+)\s*(?of\s*)?(.+)$/
这将为您提供包含计量单位的
$1
,以及包含成分的
$2

泡沫。冲洗重复
在那之后,用你的应用程序对这些信息施展魔法。

我想我应该先对每一行运行一系列正则表达式检查,然后在运行过程中调整解析的文本。例如(伪代码):

首先,检查指令:

/^(add|fold in|stir in|etc...)/
如果找到指令,请将其从行中删除,设置标志,然后继续:

instruction = $1
this_line = this_line.substring(instruction.length())
如果找到指令,检查是否有后续指令(如“和封面”或“和搁置”)

如果找到,将其剥离并插入配方的下一行之前

instruction = instruction.substring(0, instuction.length - $1.length - $2.length)
splice $2 into the array of lines immediately following this one
下一步,也许你要检查一个介词:

/((?in)to\s(.+)/
如果发现,您可以使用它来检查设备名称、碗、量杯等。 即使不使用它,也可以从正在解析的字符串中删除它,以改进匹配

最后,真正的工作是用剩下的文本完成的:

Check against /^(\d+\s+(?a\s)?\w+)\s*(?of\s*)?(.+)$/
这将为您提供包含计量单位的
$1
,以及包含成分的
$2

泡沫。冲洗重复
在那之后,用这些信息做你的应用程序能做的任何事情。

首先,我假设成分并不总是以
成分的数量单位的形式出现-否则,这将是一项非常简单的任务(只需在
之后复制子字符串即可)

这是一个困难的问题——解决办法不会很简单

我认为在这里使用正则表达式可能不是最好的方法:

  • 正如你所提到的,你必须为每种语言写很多表达 配料
  • 你可能的配料清单总是有限的 根据regex列表,如果没有 编辑更多
  • 分析某些成分将非常困难(
    奶酪,1磅(帕尔马干酪)
我认为这就是方法。你有非结构化的输入,但是在一个非常有限的环境中

也许与直觉相反,我认为找到成分的最好方法可能是不要去寻找它——而是去寻找其他的东西

  • 数字(数量)
  • 单位(磅、茶匙等)
  • 配料
而且检测数字和单位非常容易,首先识别这些数字和单位,然后提取成分应该很简单

如果您使用词性标记,很容易识别相关单词:
[('1','LS'),('pound','NN'),('of','IN'),('Beef','NNP')]

从这里开始,您可能需要使用a。为此,您需要在大量的行(例如,数百行)上手动标记成分。可能需要使用一些好的功能:

  • 单词在行中的位置
  • 存在于预先计算的成分字典中(可能使用某些部分字符串匹配度量,如
  • 词性标记器的输出
  • 单词前后(如果单词前有“of”,很可能是成分
我相信你在写了几行之后,一定能找到无数其他人

最后,我认为有些行很难处理。
1磅帕尔马干酪,1磅埃门塔尔干酪
:你必须推断第二种配料也是奶酪


至于软件,如果你能选择要使用的语言,python就有其神奇之处。我不能保证其他语言的工具包,但也许其他人会。首先,我假设成分并不总是以成分的数量单位的形式出现,否则,这将是一项非常琐碎的任务(只需在

这是一个困难的问题——解决办法不会很简单

我认为在这里使用正则表达式可能不是最好的方法:

  • 正如你所提到的,你必须为每种语言写很多表达 配料
  • 你可能的配料清单总是有限的 根据regex列表,如果没有 编辑更多
  • 分析某些成分将非常困难(
    奶酪,1磅(帕尔马干酪)
我认为这就是方法。你有非结构化的输入,但是在一个非常有限的环境中

也许与直觉相反,我认为找到配料的最好方法可能是不去寻找它——寻找所有的东西