6

我想在字符串中捕获罗马数字(低于 80 的数字就足够了)。我在How do you match only valid roman numbers with a regular expression? 中找到了很好的基础?. 问题是:它处理整个字符串。我还没有找到如何检测字符串中的罗马数字的解决方案,因为没有任何强制性,每个组都可能是可选的。到目前为止,我尝试过这样的事情:

my $x = ' some text I-LXIII iv more ';

if (  $x =~  s/\b(
                    (
                        (XC|XL|L?X{0,3}) # first group 10-90
                    |
                        (IX|IV|V?I{0,3}) # second group 1-9
                    )+
            )
        \b/>$1</xgi ) { # mark every occurrence
    say $x;
}

__END__
 ><some>< ><text>< ><>I<><-><>LXIII<>< ><>iv<>< ><more>< 
 desired output:
  some text >I<->LXIII< >iv< more 

所以,这个也可以自己捕获单词边界,因为所有组都是可选的。如何完成?如何使这两组中的一组成为强制性的,而无法分辨哪一组是强制性的?也欢迎其他捕捉罗马人的方法。

4

2 回答 2

4

您可以使用Roman CPAN 模块

use Roman;

my $x = ' some text I-LXIII VII XCVI IIIXII iv more ';
if (  $x =~  
    s/\b
    (
        [IVXLC]+
    )
    \b
    /isroman($1) ? ">$1<" : $1/exgi ) {
    say $x;
}

输出:

some text >I<->LXIII< >VII< >XCVI< IIIXII >iv< more 
于 2012-10-18T09:41:38.107 回答
2

这就是 Perl 让我们失望的地方,因为它缺少其他地方可用的\<和(开始和结束词边界)结构。即使不消耗任何目标字符串,\>类似的模式也会匹配,因为第二个模式会很高兴地第二次匹配开始的单词边界。\b...\b...\b

然而,结束词边界只是(?<=\w)(?!\w)为了我们可以使用它。

这个程序会做你想做的事。它对包含在单词边界中的一串潜在的罗马字符进行前瞻(所以我们必须在开始的单词边界处),然后检查后面没有单词字符的合法罗马数字(所以现在我们' re 在结束词边界)。

请注意,我已经颠倒了你的>...<标记,因为它们让我感到困惑。

use strict;
use warnings;

use feature 'say';

my $x = ' some text I-LXIII iv more ';

if ( $x =~ s{
    (?= \b [CLXVI]+ \b )
    (
      (?:XC|XL|L?X{0,3})?
      (?:IX|IV|V?I{0,3})?
    )
    (?!\w)
    }
    {<$1>}xgi ) {

    say $x;
}

输出

some text <I>-<LXIII> <iv> more 
于 2012-10-18T11:53:32.650 回答