我正在尝试查找并提取从文本文件中的文本文件读取的单词。到目前为止,我只能找到该单词正确书写且未蒙蒙的时候(将其更改为@或将我更改为1)。是否可以在字符串中添加正则表达式以进行匹配或类似操作?到目前为止,这是我的代码:
sub getOccurrenceOfStringInFileCaseInsensitive
{
my $fileName = $_[0];
my $stringToCount = $_[1];
my $numberOfOccurrences = 0;
my @wordArray = wordsInFileToArray ($fileName);
foreach (@wordArray)
{
my $numberOfNewOccurrences = () = (m/$stringToCount/gi);
$numberOfOccurrences += $numberOfNewOccurrences;
}
return $numberOfOccurrences;
}
该例程接收文件名和要搜索的字符串。例程wordsInFileToArray()只是从文件中获取每个单词,并返回包含它们的数组。 理想情况下,我想一次执行直接从文件读取的搜索,而不是将所有内容移动到数组并遍历整个数组。但是主要的问题是如何将一些东西硬编码到该函数中,以使我能够捕获被蒙住的单词。
示例:我想从文件中提取两行。 example.txt:
russ1 @ anh @ ck3r
russianhacker
# this variable also will be read from a blacklist file
$searchString = "russianhacker";
getOccurrenceOfStringInFileCaseInsensitive ("example.txt", $searchString);
在此先感谢您的回复。
编辑:
可能的替换将由用户定义,并且正则表达式必须设置为适合。用户可以说常见的替代方法是将字母“ a”更改为“ @”甚至“ 1”。可能的更改完全是任意的。 当搜索一个特定的单词(例如“俄语”)时,可以用类似的方法完成:
(m/russian/i); # would just match the word as it is
(m/russi[a@1]n/i); # would match the munged word
但是如果将要匹配的字符串存储在变量中,例如:
,我不确定该怎么做。$stringToSearch = "russian";
答案 0 :(得分:2)
这是一种全文搜索问题,因此一种方法是在与文档字符串匹配之前对文档字符串进行规范化。
use strict;
use warnings;
use Data::Munge 'list2re';
...
my %norms = (
'@' => 'a',
'1' => 'i',
...
);
my $re = list2re keys %norms;
s/($re)/$norms{$1}/ge for @wordArray;
这种方法仅在任何给定单词只有一种可能的“规范化形式”的情况下才有效,并且如果您的文档足够大并且您每次都重新计算一次,则其效率可能比仅尝试搜索字符串的每种可能的形式都低您搜索它。
请注意,您的正则表达式m/$randomString/gi
应该为m/\Q$randomString/gi
,因为您不希望以这种方式解释$ randomString中的任何正则表达式元字符。请参阅quotemeta的文档。
答案 1 :(得分:2)
问题的某些部分尚未得到足够准确的说明(尚未)。
取决于细节的一些自费方法是
如果用户定义的替换是全局替换(替换每个字符串中每次出现的字符),则用户可以提交映射,如哈希表所示,您可以全部修复。该过程将识别单词的所有候选单词(以及找到的实际单词,未修饰单词)。可能会有误报,因此也要计划一些后处理
如果用户可以提供替换单词列表以及适用于他们的单词(经过修饰的单词或相应的未修饰的单词),那么我们可以针对性更强地运行
在弄清楚这一点之前,这是另一种方法:使用模块进行近似(“模糊”)匹配。
String::Approx似乎很符合您的要求。
目标与给定字符串的匹配取决于 Levenshtein编辑距离的概念:将给定字符串转换为多少个插入,删除和替换(“编辑”)寻找的目标。可以设置接受的最大编辑数量。
一个简单的例子:
use warnings;
use strict;
use feature 'say';
use String::Approx qw(amatch);
my $target = qq(russianhacker);
my @text = qw(that h@cker was a russ1@anh@ck3r);
my @matches = amatch($target, ["25%"], @text);
say for @matches; #==> russ1@anh@ck3r
请参阅文档以了解该模块的用途,但至少有两个注释。
首先,请注意amatch
中的第二个参数指定了可接受的目标字符串与百分比的偏差。对于此特定示例,我们需要允许每个第四个字符都被“编辑”。如此大的调整空间可能会导致意外匹配,然后将其过滤掉,因此需要进行一些后处理。
第二个-我们没有发现更简单的h@cker
。该模块采用固定的“模式”(目标)而不是正则表达式,并且一次只能搜索一个。因此,原则上,您需要为每个目标字符串传递一个密码。可以改进很多,但是还有更多工作要做。
请研究文档;该模块提供的功能远远超过此简单示例。
答案 2 :(得分:1)
我结束了解决问题的方法,将正则表达式直接包含在将用于与文件行匹配的变量上。看起来像这样:
sub getOccurrenceOfMungedStringInFile
{
my $fileName = $_[0];
my $mungedWordToCount = $_[1];
my $numberOfOccurrences = 0;
open (my $inputFile, "<", $fileName) or die "Can't open file: $!";
$mungedWordToCount =~ s/a/\[a\@4\]/gi;
while (my $currentLine = <$inputFile>)
{
chomp ($currentLine);
$numberOfOccurrences += () = ($currentLine =~ m/$mungedWordToCount/gi);
}
close ($inputFile) or die "Can't open file: $!";
return $numberOfOccurrences;
}
所在行:
$mungedWordToCount =~ s/a/\[a\@4\]/gi;
仅仅是所需的替代之一,而其他替代可以类似地添加。 我不知道Perl只会在变量内部解释正则表达式,因为我之前已经尝试过,并且只能获得使用单引号定义函数内部变量的所需结果。第一次我一定做错了。
谢谢大家的建议。