Regex 如何捕捉字符串中的罗马数字?

Regex 如何捕捉字符串中的罗马数字?,regex,perl,Regex,Perl,我想捕捉字符串中的罗马数字(80以下的数字就足够了)。我找到了很好的基础。问题是:它处理整个字符串。我还没有找到一个解决方案,如何检测字符串中的罗马数字,因为并没有强制要求,每个组都可能是可选的。到目前为止,我试过这样的方法: my $x = ' some text I-LXIII iv more '; if ( $x =~ s/\b( ( (XC|XL|L?X{0,3}) # first group

我想捕捉字符串中的罗马数字(80以下的数字就足够了)。我找到了很好的基础。问题是:它处理整个字符串。我还没有找到一个解决方案,如何检测字符串中的罗马数字,因为并没有强制要求,每个组都可能是可选的。到目前为止,我试过这样的方法:

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 
my$x='一些文本I-LXIII-iv更多';
如果($x=~s/\b)(
(
(XC | XL | L?X{0,3})#第一群10-90
|
(IX | IV | V?I{0,3})#第二组1-9
)+
)
\b/>1美元<>>第十三条<>第四条<><
期望输出:
一些文本>ILXIII<>iv<更多
因此,这一组也可以自己捕获单词边界,因为所有组都是可选的。如何完成?如何使这两个组中的一个成为必填组,而无法区分哪一个是必填组?也欢迎使用其他捕获罗马人的方法。

您可以使用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;
}
使用罗马语;
我的$x='一些文字I-LXIII VII XCVI IIIXII iv更多';
如果($x=~
s/\b
(
[IVXLC]+
)
\b

/isroman($1)?“>$1这是Perl让我们失望的地方,因为它缺少
\
(单词的开头和结尾边界)其他位置可用的构造。类似于
\b…\b
的模式将匹配,即使
..
不使用任何目标字符串,因为第二个
\b
将再次匹配开始的单词边界


然而,结尾词的边界只是
(?一般来说,可以说
a
b
ab
,但不是什么都可以,你可以做
(a | b | ab)
(ab?| b)
,但您无法避免重复。问题:
a
b
本身由4个可选块组成。覆盖所有这些组合似乎非常疯狂。啊,对,我明白您的观点。Perl支持look aheads吗?您可以在匹配的开头(边界之后)添加一个lookahead:
(?=[IVXLDCM])
如果我有任何以这些字母开头的单词,这些边界也会被捕获。或者我做得不对,对lookaheads不太熟悉。也许你也可以试试regex,把你的代码作为答案呈现出来?对不起,我不知道Perl的第一件事(这就是为什么我把这个建议仅仅作为一个注释发布的原因)但是,再看看你的正则表达式,我认为唯一的问题是,
lx{0,3}
和它的对应项可以是空的|V
。然后结尾处的
+
应该确保边界之间没有空字符串。谢谢,但它也捕获无效序列。您在代码
(?!\w)
中使用作为结束边界,但之前您将其定义为
(?@w.k:我们要做的是找到完全由罗马字母组成的一串单词字符,然后确保它是一个有效的罗马数字。
(?!\w)
可以确保所有字符串都是有效的罗马数字,而不仅仅是前几个字符。例如,如果我们有
LXIC
,那么只有
LXI
是有效的,
(?!\w)
将不匹配,因为
C
是一个单词字符。添加
(?)?
some text >I<->LXIII< >VII< >XCVI< IIIXII >iv< more 
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