代码之家  ›  专栏  ›  技术社区  ›  João Silva

英文数字的可扩展regex

  •  5
  • João Silva  · 技术社区  · 16 年前

    我想创建一个regex来 认出 English numerals ,如 , 十九 , 二十 ,请 一百二十二 , 等等 一直到数百万人。我想 重新使用 正则表达式的某些部分,因此正则表达式是由部分构造的,例如:

    // replace <TAG> with the content of the variable
    ONE_DIGIT = (?:one|two|three|four|five|six|seven|eight|nine)
    TEEN = (?:ten|eleven|twelve|(?:thir|for|fif|six|seven|eigh|nine)teen)
    TWO_DIGITS = (?:(?:twen|thir|for|fif|six|seven|eigh|nine)ty(?:\s+<ONE_DIGIT>)?|<TEEN>)
    // HUNDREDS, et cetera
    

    我想知道是否有人已经做过同样的事情(并且愿意分享),因为这些正则表达式很长,可能它们有一些不应该做的事情,或者我可能缺少的事情。另外,我希望他们 尽可能的让我期待 优化提示 . 我使用的是JavaReX引擎,但是任何正则表达式的味道都是可以接受的。

    4 回复  |  直到 16 年前
        1
  •  8
  •   Sinan Ünür    16 年前

    见Perl Lingua::EN::Words2Nums Lingua::EN::FindNumber .

    尤其是, source code for Lingua::EN::FindNumber 包含:

    # This is from Lingua::EN::Words2Nums, after being thrown through
    # Regex::PreSuf
    my $numbers =
        qr/((?:b(?:akers?dozen|illi(?:ard|on))|centillion|d(?:ecilli(?:ard|on)|ozen|u(?:o(?:decilli(?:ard|on)|vigintillion)|vigintillion))|e(?:ight(?:een|ieth|[yh])?|leven(?:ty(?:first|one))?|s)|f(?:i(?:ft(?:een|ieth|[yh])|rst|ve)|o(?:rt(?:ieth|y)|ur(?:t(?:ieth|[yh]))?))|g(?:oogol(?:plex)?|ross)|hundred|mi(?:l(?:ion|li(?:ard|on))|nus)|n(?:aught|egative|in(?:et(?:ieth|y)|t(?:een|[yh])|e)|o(?:nilli(?:ard|on)|ught|vem(?:dec|vigint)illion))|o(?:ct(?:illi(?:ard|on)|o(?:dec|vigint)illion)|ne)|qu(?:a(?:drilli(?:ard|on)|ttuor(?:decilli(?:ard|on)|vigintillion))|in(?:decilli(?:ard|on)|tilli(?:ard|on)|vigintillion))|s(?:core|e(?:cond|pt(?:en(?:dec|vigint)illion|illi(?:ard|on))|ven(?:t(?:ieth|y))?|x(?:decillion|tilli(?:ard|on)|vigintillion))|ix(?:t(?:ieth|y))?)|t(?:ee?n|h(?:ir(?:t(?:een|ieth|y)|d)|ousand|ree)|r(?:e(?:decilli(?:ard|on)|vigintillion)|i(?:gintillion|lli(?:ard|on)))|w(?:e(?:l(?:fth|ve)|nt(?:ieth|y))|o)|h)|un(?:decilli(?:ard|on)|vigintillion)|vigintillion|zero|s))/i;
    

    从属于 Perl's Artistic License .

    你可以使用 Regex::PreSuf 要自动排除常见的前缀和后缀:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use Regex::PreSuf;
    
    my %singledigit = (
        one    => 1,
        two    => 2,
        three  => 3,
        four   => 4,
        five   => 5,
        six    => 6,
        seven  => 7,
        eight  => 8,
        nine   => 9,
    );
    
    my $singledigit = presuf(keys %singledigit);
    
    print $singledigit, "\n";
    
    my $text = "one two three four five six seven eight nine";
    
    $text =~ s/($singledigit)/$singledigit{$1}/g;
    
    print $text, "\n";
    

    输出:

    C:\Temp> cvb
    (?:eight|f(?:ive|our)|nine|one|s(?:even|ix)|t(?:hree|wo))
    1 2 3 4 5 6 7 8 9
    

    恐怕以后会更难了;—)

        2
  •  3
  •   ysth    16 年前

    Perl具有许多模块,这些模块可以使用不同的技术来生成优化的正则表达式(主要只使用标准特征,因此应该在Java中可用)。您可以在中看到regexp::assembly、regexp::list、regexp::optimizer和regex::presuf输出的示例。 http://groups.google.com/group/perl.perl5.porters/msg/132877aee7542015 . 从Perl5.10开始,Perl本身通常优化 | 将字符串精确到trie中。

        3
  •  0
  •   Rob Jones    16 年前

    你想做什么?你在使用什么算法?

    我不熟悉Java正则表达式引擎,但是我使用的其他ReX引擎(Perl,AWK)允许您捕获匹配。例如,如果您尝试匹配:

    一百一十万

    你可以有一个regex,它可以识别一百万,它之前的任何东西(即“一”),以及它之后的所有东西(即“十万一百”)。之前的内容将被捕获以进行额外的匹配(使用您的数百、数十和一个regex),之后的内容将被捕获以进行额外的匹配(使用您的数千个regex、数百个regex、数十个regex或一个regex)。

    这个算法是自然递归的,并且不会太难实现。不知道你想要完成的细节或Java的正则表达式引擎的细节,我不能提出更多的建议。

        4
  •  0
  •   Noon Silk    16 年前

    Regex真的是一个糟糕的方法。就我个人而言,我只需要创建一个所有已知单词的小地图,并以这种方式进行搜索。(搜索每个词,当你找到一个匹配词时,确定它旁边的词是否匹配,然后继续搜索直到你有了数字)。