给出一行如
1磅牛肉
我想提取这种成分。最初我只对成分名称感兴趣。
我看过rubys着名的时间解析器Chronic并喜欢它使用正则表达式。
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
端
然而在我的情况下,Id可能必须为每种成分创建超过300个正则表达式。
我还必须考虑诸如 Cilantro& amp;等同义词。 Corriander Leaf
我以前从未进行过解析,但是在这里使用正则表达式仍然是最好的方法。我想不出任何其他合理的选择。
答案 0 :(得分:3)
首先,我假设成分并不总是采用QUANTITY UNIT of INGREDIENT
的形式 - 否则,这将是一项非常简单的任务(只需复制of
之后的子串
这是一个难题 - 解决方案并不简单。
我认为使用正则表达式可能不是最好的方法:
cheese, 1 pound (parmesan)
)我认为natural language processing是前往此的方式。您有非结构化输入,但在非常有限的环境中。
也许与直觉相反,我认为找到这种成分的最佳方式可能是不寻找它 - 而是寻找其他一切。如果你假设一条线总是
并且检测数字和单位非常容易,首先要识别它们然后然后提取成分应该是直截了当的。
如果您使用词性标注器,则可以轻松识别相关字词:
[('1', 'LS'), ('pound', 'NN'), ('of', 'IN'), ('Beef', 'NNP')]
从那里,您可能想要使用classifier。为此,您需要在大量的线条(例如数百个)上手动标记成分。一些可能使用的好功能:
我确信在完成几行工作后你将能够找到无数其他人。
最后,我希望有些线路很难处理。 1 pound of parmesan cheese, 1 pound of emmentaler
:你必须推断第二种成分也是奶酪。
对于软件,如果你可以选择使用的语言,python就会有很棒的Natural Language Toolkit。我不能保证其他语言的工具包,但也许别人会。
答案 1 :(得分:1)
我想我会先对每一行运行一系列正则表达式检查,然后调整解析后的文本。例如(伪代码):
首先,检查说明:
/^(add|fold in|stir in|etc...)/
如果找到了指令,请将其从行中删除,设置一个标志,然后继续:
instruction = $1
this_line = this_line.substring(instruction.length())
如果找到了指令,请检查是否有后续指令(例如"并覆盖"或"并留出")
/\b(and\s)(.*)$/
如果找到,请将其剥离并在配方的下一行
之前插入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
包含成分。
泡沫。冲洗。重复。 在那之后,做你的应用程序对这些信息所做的任何魔术。
答案 2 :(得分:0)
首先,我建议进行搜索以查看是否有人已经为该问题创建了一个解决方案,足以供您使用,而不是重新发明轮子。
例如,您可能会发现this project很有趣。它使用机器学习来尝试解析成分短语,包括成分类型和数量。
在搜索“成分分析器”时也会出现其他有趣的项目。
如果您真的决心自己编写此代码,那么建议您对称为“解析器生成器”的软件工具类别进行一些研究,该工具可让您编写所需的语言。以抽象形式(“语法”)识别,然后将以您选择的语言生成代码,该代码将根据该语法解析文本,并将非常高效地识别其中的特定子结构(比数百种方法要高效得多)正则表达式匹配)。
例如,用作解析器生成器输入的语法可能看起来像这样:
// I am making up the following syntax for demonstration purposes, but it illustrates the
// sort of things that one could specify in a grammar, and is not terribly different from
// the grammar languages that real parser generators use.
//
// Note that everything in the curly braces is code to be inserted into the generated parser.
// Each such code block will be invoked when the preceding parsing rule is matched.
%declare { bool organic=false; bool dried=false; bool smoked=false; }
INGREDIENT ::= "organic" INGREDIENT { organic=true; }
| INGREDIENT "(" "organic" ")" { organic=true; }
| "dried" INGREDIENT { dried=true; }
| "smoked" INGREDIENT { smoked=true; }
| AMOUNT "of" INGREDIENT
| INGREDIENT "(" AMOUNT ")"
| BASE_INGREDIENT
BASE_INGREDIENT ::= ( WORD )* {
doSomethingWithBaseIngredient(organic, dried, smoked, $BASE_INGREDIENT);
}
AMOUNT ::= NUMBER ( VOLUME_UNIT | WEIGHT_UNIT )
VOLUME_UNIT ::= "cup" | "liter"
WEIGHT_UNIT ::= "mg" | "kg" | "pound"
NUMBER ::= [0-9]+
WORD ::= [a-zA-Z]+
... and so forth.
解析器生成器在运行时将以该语法作为输入,并以您所需的编程语言生成代码作为输出。此代码将根据语法解析输入文本,并且在匹配某些解析规则时,还可根据需要设置变量和/或调用函数。由此类工具生成的解析器通常使用特殊的解析技术(通常涉及大型表,状态机等)来高效地解析一次,而不必做多余的工作,并在可能的情况下避免回溯。>
解析器生成器的一些常见示例是lexx / yacc,bison和Antlr。存在许多其他。 (就我个人而言,过去我在Antlr上取得了不错的成绩,并且特别喜欢它可以以许多不同的编程语言生成解析器的事实。)这些解析器生成器中的许多主要供编译器作者使用,但是确实如此。并不意味着它们不能用于其他目的,例如识别食谱中成分的各种形式。
This article提供了解析器生成器的概述,并且this article包含了各种解析器生成器及其属性(输出语言等)的表,以及有关在何处查找更多内容的链接。