我有一个源字符串,可能包含任何字符,包括空格,回车符和换行符(控制字符)。控制字符可以出现在包括单词中间的任何地方。
我有一个搜索字符串,可能与源字符串具有相同的字符选择,但通常是源的子字符串。此搜索字符串中控制字符的顺序和数量可能与来源不同。
当搜索字符串中的非控制字符匹配时,我需要从源字符串中删除该字符串,包括字符串中的任何控制字符。不应删除源字符串中其他位置的控制字符。
我的计划是在搜索字符串中的每个字符后添加\s*
。这很好,但是我需要在搜索字符串中转义任何正则表达式特殊字符,否则它们将被视为正则表达式命令,而不是纯文本。
我可以在每个字符(\s*
)之后添加'mytext.scan(/./).join("\\s*")'
但是如何转义特殊字符而不是我插入的正则表达式代码?如果我反过来这样做,那么我可以逃避正则表达式的特殊字符,但我不能简单地在每个字符之后添加\s*
;我需要避免逃脱的角色。
为清楚起见 控制字符=空格或\ t或\ r \ n或\ n或\ f
编辑:修改第3段以提高我的要求的清晰度
答案 0 :(得分:0)
一种天真的方法是
1)将搜索字符串拆分为单个字符列表(每个字符串)
2)清理每个角色(仍然是一个字符串列表)
3)按\s*
*
*除了\s*
不起作用,顺便说一下 - \s*
将匹配0个或更多的空格,这与0个或更多个控制字符不同。请参阅http://www.regular-expressions.info/posixbrackets.html#class,并使用适用于正则表达式的“控制字符”形式:)
\W*
也可能有用,因为\W
是不在a-zA-Z0-9_中的任何字符。但我从未测试过是否匹配控制字符或仅打印字符。
答案 1 :(得分:0)
评论中讨论的或多或少:
制作源字符串和搜索字符串的副本。消除两个副本中的所有控制字符。使用源字符串副本中的搜索字符串副本进行搜索。如果需要(或重音删除,或......),您也可以进行大小写转换。使用大量
\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
是源的另一个副本。 $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)生日',这似乎符合要求。
将其转换为Ruby是留给受虐待者的一种练习。
显然,您可以简单地创建并使用$r_search
字符串作为正则表达式,并将其直接应用于$source
的副本;它会奏效。但我非常怀疑,如果你将它应用于千字节长度的源字符串,代码将运行得非常慢。我没有做过测量来证明它。