10
4

1 回答 1

5

编辑:我只是注意到您实际上并没有指定您使用的是哪种模式匹配语言。好吧,我希望 Perl 解决方案对您有用,因为所需的机制在任何其他语言中都可能非常困难。另外,如果您使用 Unicode 进行模式匹配,Perl 确实是该特定工作的最佳选择。


$rx下面的变量设置为适当的模式时,这个 Perl 代码的小片段:

my $data = "foo1 and Πππ 語語語 done";

while ($data =~ /($rx)/g) {
   print "Got string: '$1'\n"; 
} 

生成此输出:

Got string: 'foo1 and '
Got string: 'Πππ '
Got string: '語語語 '
Got string: 'done'

也就是拉出一个拉丁字符串,一个希腊字符串,一个汉字符串,一个拉丁字符串。这与我认为您真正需要的东西非常接近。

我昨天没有发布这个的原因是我得到了奇怪的核心转储。现在我知道为什么了。

(??{...})我的解决方案在构造内部使用词法变量。事实证明,这在 v5.17.1 之前是不稳定的,充其量只能是偶然的。它在 v5.17.0 上失败,但在 v5.18.0 RC0 和 RC2 上成功。所以我添加了一个use v5.17.1来确保你运行的东西足够新,可以信任这种方法。

首先,我决定您实际上并不想要运行所有相同的脚本类型;您想要运行所有相同的脚本类型以及Common 和 Inherited。否则,Common 的标点符号、空格和数字以及 Inherited 的组合字符将搞砸。我真的不认为你希望那些打断你运行“所有相同的脚本”,但如果你这样做,很容易停止考虑这些。

所以我们要做的是先行查找脚本类型不是 Common 或 Inherited 的第一个字符。不仅如此,我们从中提取该脚本类型实际上是什么,并使用此信息构建一个新模式,该模式是任意数量的字符,其脚本类型是通用的、继承的或我们刚刚找到并保存的任何脚本类型。然后我们评估新模式并继续。

嘿,我说它有毛,不是吗?

在我将要展示的程序中,我留下了一些注释掉的调试语句,这些语句显示了它在做什么。如果您取消注释它们,您将获得最后一次运行的输出,这应该有助于理解该方法:

DEBUG: Got peekahead character f, U+0066
DEBUG: Scriptname is Latin
DEBUG: string to re-interpolate as regex is q{[\p{Script=Common}\p{Script=Inherited}\p{Script=Latin}]*}
Got string: 'foo1 and '
DEBUG: Got peekahead character Π, U+03a0
DEBUG: Scriptname is Greek
DEBUG: string to re-interpolate as regex is q{[\p{Script=Common}\p{Script=Inherited}\p{Script=Greek}]*}
Got string: 'Πππ '
DEBUG: Got peekahead character 語, U+8a9e
DEBUG: Scriptname is Han
DEBUG: string to re-interpolate as regex is q{[\p{Script=Common}\p{Script=Inherited}\p{Script=Han}]*}
Got string: '語語語 '
DEBUG: Got peekahead character d, U+0064
DEBUG: Scriptname is Latin
DEBUG: string to re-interpolate as regex is q{[\p{Script=Common}\p{Script=Inherited}\p{Script=Latin}]*}
Got string: 'done'

最后是一件大事:

use v5.17.1;
use strict;
use warnings;
use warnings FATAL => "utf8";
use open qw(:std :utf8);
use utf8;

use Unicode::UCD qw(charscript);

# regex to match a string that's all of the
# same Script=XXX type
#
my $rx = qr{
    (?=
       [\p{Script=Common}\p{Script=Inherited}] *
        (?<CAPTURE>
            [^\p{Script=Common}\p{Script=Inherited}]
        )
    )
    (??{
        my $capture = $+{CAPTURE};
   #####printf "DEBUG: Got peekahead character %s, U+%04x\n", $capture, ord $capture;
        my $scriptname = charscript(ord $capture);
   #####print "DEBUG: Scriptname is $scriptname\n";
        my $run = q([\p{Script=Common}\p{Script=Inherited}\p{Script=)
                . $scriptname
                . q(}]*);
   #####print "DEBUG: string to re-interpolate as regex is q{$run}\n";
        $run;
    })
}x;


my $data = "foo1 and Πππ 語語語 done";

$| = 1;

while ($data =~ /($rx)/g) {
   print "Got string: '$1'\n";
}

是的,应该有更好的方法。我认为还没有。

所以现在,享受吧。

于 2013-05-14T00:14:40.690 回答