编辑:我刚刚注意到您实际上没有指定您使用的
哪种模式匹配语言。希望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或刚刚找到并保存的脚本类型。然后我们评估该新模式并继续。
嘿,我说过它很麻烦,不是吗?
在即将展示的程序中,我保留了一些已注释的调试语句,以显示它正在做什么。如果您取消对它们的注释,您将获得最后一次运行的输出,这应该有助于理解方法:
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);
my $rx = qr{
(?=
[\p{Script=Common}\p{Script=Inherited}] *
(?<CAPTURE>
[^\p{Script=Common}\p{Script=Inherited}]
)
)
(??{
my $capture = $+{CAPTURE};
my $scriptname = charscript(ord $capture);
my $run = q([\p{Script=Common}\p{Script=Inherited}\p{Script=)
. $scriptname
. q(}]*);
$run;
})
}x;
my $data = "foo1 and Πππ 語語語 done";
$| = 1;
while ($data =~ /($rx)/g) {
print "Got string: '$1'\n";
}
是的,应该有更好的方法。 我认为目前还没有。
所以现在就先享受吧。