或多或少地在评论中讨论:
复制源字符串和搜索字符串。消除两个副本中的所有控制字符。在源字符串的副本中使用搜索字符串的副本进行搜索。如果需要(或重音删除,或...),您也可以进行大小写转换。使用很多\s*
可能会大大减慢您的正则表达式。
搜索字符串只需要复制和预处理一次。每个源字符串也需要复制和预处理一次。如果最坏的情况出现在最坏的情况下,当您知道有匹配项时,您可以返回原始源字符串并制作搜索字符串的新副本,以便您\s*
在每个常规字符之间确实有类似的东西,并应用正则表达式从搜索字符串的第二个(残缺)副本到原始源字符串。因为你知道有一个匹配,所以性能应该是合理的,即使失败匹配模式太慢了。
这是所讨论的想法的 Perl 实现。
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
$Data::Dumper::Useqq = 1;
my $source = "'Twas (Tweedle-Dee's)\fBirthday\n\n\f\f\nand\ta\tl\tl\this friends were happy\n";
my $search = "(\fTwee\ndle\t-\tDee\r'\rs)\nBi\frth\fday";
print Data::Dumper->Dump([$source], [qw($source)]);
print Data::Dumper->Dump([$search], [qw($search)]);
my $c_source = $source;
my $c_search = $search;
$c_source =~ s/ |[[:cntrl:]]//g; # Or s/\s//g;
$c_search =~ s/ |[[:cntrl:]]//g; # Or s/\s//g;
print Data::Dumper->Dump([$c_source], [qw($c_source)]);
print Data::Dumper->Dump([$c_search], [qw($c_search)]);
if ($c_source =~ m/\Q$c_search\E/)
{
# Locating the search in the original source...hard work...
my @a_search = split //, $c_search;
printf "Lengths: c_search %d; a_search %d\n", length($c_search), scalar(@a_search);
@a_search = map { s/[][\\.*?+(){}]/\\$&/g; $_ } @a_search; # Escape regex metacharacters
#print Data::Dumper->Dump([\@a_search], [qw(@a_search)]);
my $r_search = join "\\s*", @a_search;
print Data::Dumper->Dump([$r_search], [qw($r_search)]);
my $t_source = $source;
$t_source =~ s/$r_search//g;
print Data::Dumper->Dump([$t_source], [qw($t_source)]);
}
好干净的象形文字乐趣——毫无疑问,像泥巴一样清晰。前三行检查没有任何愚蠢的错误。Data::Dumper
模块明确打印数据;它在那里进行调试。该Useqq
变量会调整数据的明确打印方式。
变量$source
和$search
是源字符串和搜索字符串。有一个匹配,尽管它们每个都有所有控制字符。请注意,混合中有一些正则表达式元字符——括号是正则表达式元字符。这些字符串被转储以供参考。
接下来的两行复制了搜索字符串和源字符串。控制字符和空格被删除,使用基于 POSIX 的正则表达式类来指定所有控制字符。这些转换后的字符串被转储以供检查。
该if
语句将转换后的源与转换后的搜索进行比较。这些\Q...\E
部分抑制了正则表达式元字符之间的含义。如果匹配,那么我们在大括号中输入代码块。
该split
操作从转换后的搜索字符串创建单个字符数组。printf
检查理智。该map
操作将每个正则表达式元字符替换为反斜杠和元字符,而其他字符保持不变。将join
数组中的每个字符或字符对收集@a_search
到一个字符串$r_search
中,并\s*
分隔数组条目。
该变量$t_source
是源的另一个副本。正则表达式 in$r_search
被应用于$t_search
并且任何匹配都被替换为空。结果被转储。该脚本的输出是:
$source = "'Twas (Tweedle-Dee's)\fBirthday\n\n\f\f\nand\ta\tl\tl\this friends were happy\n";
$search = "(\fTwee\ndle\t-\tDee\r'\rs)\nBi\frth\fday";
$c_source = "'Twas(Tweedle-Dee's)Birthdayandallhisfriendswerehappy";
$c_search = "(Tweedle-Dee's)Birthday";
Lengths: c_search 23; a_search 23
$r_search = "\\(\\s*T\\s*w\\s*e\\s*e\\s*d\\s*l\\s*e\\s*-\\s*D\\s*e\\s*e\\s*'\\s*s\\s*\\)\\s*B\\s*i\\s*r\\s*t\\s*h\\s*d\\s*a\\s*y";
$t_source = "'Twas \n\n\f\f\nand\ta\tl\tl\this friends were happy\n";
该字符串$t_source
确实对应于$source
删除 '(Tweedle-Dee's) Birthday',这似乎符合要求。
将其转换为 Ruby 留给受虐狂^H^H^H^H^H^H^H^H^H^H^H 感兴趣的读者作为练习。
显然,您可以简单地创建$r_search
字符串并将其用作正则表达式并将其直接应用于 (a copy of) $source
; 它会起作用的。但我非常怀疑,如果将它应用于千字节长度的源字符串,代码运行速度会非常慢。不过,我还没有进行测量来证明这一点。