Regex 模糊正则表达式

Regex 模糊正则表达式,regex,perl,fuzzy-comparison,Regex,Perl,Fuzzy Comparison,我正在寻找一种使用正则表达式进行模糊匹配的方法我想使用Perl,但如果有人能推荐任何一种方法,那将非常有用。 例如,我想匹配单词“newyork”上的一个字符串,前面是一个2位数的数字。困难是因为文本来自PDF的OCR,所以我想做一个模糊匹配。我想匹配: 12 New York 24 Hew York 33 New Yobk 和其他“接近”匹配(在Levenshtein距离的意义上),但不是: aa New York 11 Detroit 显然,我需要为匹配指定允许的距离(“模糊性”) 据我

我正在寻找一种使用正则表达式进行模糊匹配的方法我想使用Perl,但如果有人能推荐任何一种方法,那将非常有用。

例如,我想匹配单词“newyork”上的一个字符串,前面是一个2位数的数字。困难是因为文本来自PDF的OCR,所以我想做一个模糊匹配。我想匹配:

12 New York
24 Hew York
33 New Yobk
和其他“接近”匹配(在Levenshtein距离的意义上),但不是:

aa New York
11 Detroit
显然,我需要为匹配指定允许的距离(“模糊性”)

据我所知,我不能使用
String::appro
Perl模块来实现这一点,因为我需要在匹配中包含一个正则表达式(以匹配前面的数字)

另外,我应该注意到,这是一个非常简单的例子,说明了我真正想要匹配的东西,所以我不寻求暴力方法

编辑以添加:

好吧,我的第一个例子太简单了。我的意思不是让人们挂断前面的数字——很抱歉这个坏例子。这里有一个更好的例子。考虑这个字符串:

由MESHS ASSIGN1IBNTS向ALUSCHALME&S MANOTAC/rURINGCOMPANY转让人,一家延期/延期的公司。

这实际上说明:

转让人,由MESNE ASSIGNMENTS向特拉华州的一家公司ALLIS-CHALMERS制造公司转让

我需要做的是提取短语“ALUSCHALME&S MANOTAC/rURINGCOMPANY”和“DELAY/ABE”。(我意识到这似乎有点疯狂。但我是一个乐观主义者。)一般来说,这种模式会是这样的:

while(<>) {
  chomp;
  if(/assignor, by (\w+) (\w+), to (\w+), a (\w+) of (\w+)/i) {
    # now use String::Approx to check that $1, $2, $3, $4, and $5 match
  } else {
    warn "Errors!\n";
  }
}
/Assignor(,通过mesne assignments,)?致(公司名称),一家(州)/i的公司


匹配是模糊的。

您是否考虑过两阶段测试,使用regex强制执行
[0-9]{2,2}(.*)
的要求,然后捕获剩余文本并对其进行模糊匹配?试着把这个问题想象成正则表达式和模糊字符串的交集。

正则表达式有特定的规则,它们不是为做你想做的事情而构建的。两次传球会容易得多。使用正则表达式去除数字,然后使用模块接近匹配

类似这样的情况(假设您的输入是来自文件的行)

while(我的$line=){
chomp$行;
#我们有数字吗?
如果($line=~/^\d+/){
#删除行首的空格和数字
$line=~s/^[\d\s]*//g;
#使用模块确定剩余文本中是否有匹配项。
如果(模块匹配){
#做点什么
}
否则{
#没有对手
}
}
否则{
#没有对手
}
}

将问题分为两部分:

  • 匹配两位数的数字
  • 模糊地将剩余部分与“纽约”匹配
  • 在本例中,您知道“纽约”由两个单词组成;你也许可以利用这一点更容易地消除像“底特律”(但不一定是“旧金山”)这样的替代品

    您甚至可以使用“”,尽管它提到:

    。。。CPAN中的Text::Levenshtein和Text::LevenshteinXS模块。另请参见Text::WagnerFischer和Text::PhraseDistance


    (我的Perl无法通过CPAN找到Text::PhraseDistance-其他的都可以使用,安装也可以。)

    您可以通过与限制进行比较来缩小候选对象的范围,以获得编辑距离和grepping

    但另一个想法是,您可以采用正确的形式,并根据指向正确形式的未遂事件创建一个哈希键,以便这些未遂事件也可以成为候选

    对于正则表达式,您可能必须使用实验代码部分,可能类似于:

    m/ (?i: [new] | \p{Alpha} (?{ $misses++ }) ){2,4}
       \s+
      (?i: [york] | \p{Alpha} (?{ $misses++ }) ){3,5}
     /x
    

    虽然在这种情况下,您可能需要为每个适当的值设置一个正则表达式。您可能需要一些标志来指示何时未达到目标。

    您可以尝试使用类似和条件可能性最大化的方法


    <如果我记得正确的话,第14章致力于这个数据集,以及如何使用它来发现拼写错误等。

    < P>经验法则:当你必须去栈溢出时,问“我如何在一个正则表达式中做X?”,你应该考虑做X不只是一个正则表达式。 根据您的编辑,我会这样做:

    while(<>) {
      chomp;
      if(/assignor, by (\w+) (\w+), to (\w+), a (\w+) of (\w+)/i) {
        # now use String::Approx to check that $1, $2, $3, $4, and $5 match
      } else {
        warn "Errors!\n";
      }
    }
    
    while(){
    咀嚼;
    如果(/assignor,by(\w+)(\w+),to(\w+),则(\w+)/i的(\w+){
    #现在使用String::Approx检查$1、$2、$3、$4和$5是否匹配
    }否则{
    警告“错误!\n”;
    }
    }
    
    我不会把这里的一切都给你。我没有将(\w+)(\w+)
    位设置为可选的
    ”,以简化正则表达式,这样您就可以了解它的要点。为此,您可能需要使用命名捕获和
    (?:)
    非捕获组。我不想深入研究所有这些,只是想帮助你理解我将如何处理这件事


    请记住:如果您必须问“如何在单个正则表达式中完成所有操作?”您应该停止在单个正则表达式中完成所有操作。

    尽管您指定了perl,但R中内置了一个有用的算法,可实现Levenshtein编辑距离

    agrep()
    

    此命令还允许使用任何正则表达式或模式进行匹配。我建议你看看

    您是否考虑过在CPAN上使用模块?它有
    agrep
    算法,但比Udi慢得多。

    如果你有一个模式你想找到文本集合的最佳匹配,你可以尝试q-gram距离。它很容易实施,并适应特殊需要

    您的第二个描述实际上在这里很有用,因为模式和文本应该相当长。q-gram距离对“York”这样的词不起作用,但如果你的典型模式是一个完整的地址
    The fuzziness of a regex item is specified between “{” and “}” after the item.
    
    Examples:
    
    foo match “foo” exactly
    (?:foo){i} match “foo”, permitting insertions
    (?:foo){d} match “foo”, permitting deletions
    (?:foo){s} match “foo”, permitting substitutions
    (?:foo){i,s} match “foo”, permitting insertions and substitutions
    (?:foo){e} match “foo”, permitting errors
    If a certain type of error is specified, then any type not specified will not be permitted.
    
    In the following examples I’ll omit the item and write only the fuzziness:
    
    {d<=3} permit at most 3 deletions, but no other types
    {i<=1,s<=2} permit at most 1 insertion and at most 2 substitutions, but no deletions
    {1<=e<=3} permit at least 1 and at most 3 errors
    {i<=2,d<=2,e<=3} permit at most 2 insertions, at most 2 deletions, at most 3 errors in total, but no substitutions
    
    import regex, pprint
    
    m = regex.compile( r'(?:Assignor(, by mesne assignments,)? to (company name), a corporation of (state)){e}', regex.IGNORECASE ).match('ASSIGNOR, BY MESHS ASSIGN1IBNTS, TO ALUSCHALME&S MANOTAC/rURINGCOMPANY, A COBPOBATlOH OF DELAY/ABE.')
    
    pprint.pprint(m)
    pprint.pprint(m.groups())
    
    <regex.Match object; span=(0, 71), match='ASSIGNOR, BY MESHS ASSIGN1IBNTS, TO ALUSCHALME&S MANOTAC/rURINGCOMPANY,', fuzzy_counts=(45, 0, 0)>
    (', BY MESHS ASSIGN1IBNTS', ' ALUSCHALME&', 'PANY,')