1 回答
编辑:我只是注意到您实际上并没有指定您使用的是哪种模式匹配语言。好吧,我希望 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";
}
是的,应该有更好的方法。我认为还没有。
所以现在,享受吧。