正则表达式匹配文件中的唯一单词

时间:2009-11-03 08:15:05

标签: regex linux perl grep

要在文件中使用“UNIQUE:”作为前缀的唯一单词,我尝试使用perl regex命令,如:

perl -e 'undef $/;while($_=<>){s/^(((?!\b\3\b).)*)\b(\w+)\b(((?!\b\3\b).)*)$/\1UNIQUE:\3\4/gs;print $_;}' demo

在包含以下内容的演示文件中

watermelon banana
apple pear pineapple orange mango
strawberry cherry
kiwi pineapple lemon cranberry watermelon
orange plum cherry
kiwi banana plum
mango cranberry apple
lemon

输出结果为:

watermelon banana
apple pear pineapple orange mango
strawberry cherry
kiwi pineapple lemon cranberry watermelon
orange plum cherry
kiwi banana plum
mango cranberry apple
UNIQUE:lemon

不幸的是,如果提前使用,似乎无法处理 \ 3 反向引用。

是否有另一种方法可以通过另一个正则表达式或 Linux 框中提供的其他常用命令来实现此目的? (grep,sed,awk,...)

非常感谢

修改 不幸的是,许多解决方案仅适用于所提供的案例而且不完整,我为此道歉,它也应该适用于以下文本:

{watermelon || banana}
apple = ( pear pineapple orange mango )
strawberry cherry
kiwi = pineapple = lemon = cranberry = watermelon
orange - plum = cherry
kiwi = banana + plum
mango = cranberry && apple
lemon

如果它简化了问题,单词可能会以$或@为前缀。

5 个答案:

答案 0 :(得分:13)

我看到你已经在使用Perl了。当你想用哈希计算某些东西总是一个很好的方法......

#!/usr/bin/perl -w
use strict;

my %hash = ();
my $str;

while(<>) {
    $str .= $_;
    $_ =~ s/\W+/ /g;
    map {$hash{$_}++} split ' ', $_;
}

for (keys %hash){
    my $word = $_;
    if($hash{$word}==1) {
        $str =~ s/\($word)/UNIQUE:$word/g;
    }
};

print "$str\n";

将输出:

{watermelon || banana}
apple = ( UNIQUE:pear pineapple orange mango )
UNIQUE:strawberry cherry
kiwi = pineapple = lemon = cranberry = watermelon
orange - plum = cherry
kiwi = banana + plum
mango = cranberry && apple
lemon

使用正则表达式可能会很难。您需要两次运行整个文件。一次通过计算所有出现的单词和一次通过来标记唯一单词。

上面的代码片段读取输入一次,但是将整个原始文本保存在$ str中 - 如果输入很大,这显然是一个坏主意。

答案 1 :(得分:5)

单次执行regexp是不可能的。这样做的原因是因为在第一次替换完成后,内部游标在该匹配结束时移动,并且下次开始匹配时会忘记它背后的内容。事实上,不支持动态后视,因此您无法检查“此单词是否已在此匹配位置之前出现”。但是,你可以做的是每次执行正则表达式替换一个单词(因为这样你总是可以在字符串的开头锚定)。所以你要做的就是运行以下正则表达式,只要它取代了什么。

s/^.*?\K(?!UNIQUE:)\b(\w+)\b(?=(?:(?!\b\1\b).)*$)/UNIQUE:\1/s

答案 2 :(得分:2)

请注意,您需要更换操作的边界;否则,唯一的apple可能会与非唯一cranapple发生冲突,例如。

use strict;
use warnings;
use File::Slurp qw(read_file);

my %words;
my $content = read_file(shift @ARGV);
$words{$_} ++ for split /[\s\W]+/, $content;
my @uniq = grep { $words{$_} == 1 and length } keys %words;
$content =~ s/\b$_\b/UNIQUE:$_/g for @uniq;
print $content;

答案 3 :(得分:1)

我不知道为什么“柠檬”是独一无二的,但是我只想假设它只是一个单词出现,那么这里是一个awk脚本

awk '{
 for(i=1;i<=NF;i++){
    words[$i]++
    if( words[$i] > 1){   delete words[$i]  }
 }
 a[++d]=$0
}END{
 for(i=1;i<=d;i++){
    m=split(a[i],t," ")
    for(k=1;k<=m;k++){
        if ( t[k] in words ) {
            t[k]="UNIQUE:"t[k]
        }
    }
    for(w=1;w<=d;w++){
        printf "%s ",t[w] 
    }
    print ""
 }
}' file

输出

$ more file
watermelon banana
apple pear pineapple orange mango
strawberry cherry
kiwi pineapple lemon cranberry watermelon
orange plum cherry
kiwi banana plum
mango cranberry apple
lemon

$ ./shell.sh
watermelon banana
apple UNIQUE:pear pineapple orange mango
UNIQUE:strawberry cherry
kiwi pineapple lemon cranberry watermelon
orange plum cherry
kiwi banana plum
mango cranberry apple
lemon

答案 4 :(得分:0)

你能把每个字放在一行吗?如果可以,您可以使用命令 uniq

uniq -c yourfile

这样每个唯一单词的计数为1。