EDIT:我只是注意到你实际上并没有具体说明which您正在使用的模式匹配语言。好吧,我希望 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'
也就是说,它会拉出一个拉丁字符串、一个希腊字符串、一个汉字字符串和另一个拉丁字符串。这与我认为你真正需要的东西非常接近。
我昨天没有发布这个的原因是我得到了奇怪的核心转储。现在我知道为什么了。
我的解决方案在 a 内部使用词汇变量(??{...})
构造。事实证明,这在 v5.17.1 之前是不稳定的,最多只是偶然起作用。它在 v5.17.0 上失败,但在 v5.18.0 RC0 和 RC2 上成功。所以我添加了一个use v5.17.1
确保您正在运行足够新的东西以信任这种方法。
首先,我认为您实际上并不想要运行所有相同的脚本类型;您想要运行所有相同的脚本类型plus共同的和继承的。否则,您将因 Common 的标点符号、空格和数字以及 Inherited 的组合字符而变得混乱。我真的不认为你希望这些中断你运行“所有相同的脚本”,但如果你这样做,很容易停止考虑这些。
因此,我们要做的是向前查找脚本类型不是 Common 或 Inherited 的第一个角色。更重要的是,我们从中提取脚本类型的实际内容,并使用此信息构建一个新模式,该模式是任意数量的字符,其脚本类型可以是“通用”、“继承”或我们刚刚找到并保存的任何脚本类型。然后我们评估新模式并继续。
Hey, I said它是毛茸茸的,不是吗?
在我即将展示的程序中,我留下了一些注释掉的调试语句,这些语句显示了它正在做什么。如果取消注释它们,您将获得上次运行的输出,这应该有助于理解该方法:
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";
}
是的,应该有更好的方法。我认为目前还没有。
所以现在,享受吧。