2009-11-03 21 views
3

要使用獨特的前綴詞「獨一無二的:」在文件中,我試圖用一個Perl的正則表達式的命令,如:正則表達式匹配的唯一字的文件中

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 

如果它簡化了問題,也就是說可以用類似$或前綴@。

+1

請注意,此演示文件中只有「梨」和「草莓」是唯一的。 「undef $ /」用於整個讀取文件而不是逐行讀取。 (((!!foo)。)*)通常用於匹配任何不包含「foo」的東西。 – 2009-11-03 08:20:57

回答

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中的所有原始文本 - 顯然是一個糟糕的主意,如果輸入的是大的。

+0

替換操作需要單詞邊界。要查看問題,請添加另一個數據項:'berry'。 – FMc 2009-11-07 12:08:44

+0

很好的結果,我在正則表達式 – 2009-11-07 20:55:52

0

你可以把每一個字一個線?如果你能,你可以使用命令uniq的

uniq -c yourfile 

這樣,每一個獨特的字將有1

+0

不幸的是,我真的不得不在原始文件中用「UNIQUE:」之類的標記來標記獨特的單詞。 – 2009-11-03 08:38:33

+0

uniq報告或過濾掉文件中的重複行,而不是文字。 – 2009-11-03 12:14:19

5

這是無法實現的正則表達式的一次執行這樣做。這樣做的原因是因爲第一個替換完成後的內部光標在那場比賽結束移動,並在下一次開始匹配它忘記了什麼是它背後。正如它的情況那樣,不支持動態後視,所以你不能檢查「這個詞已經出現在這個匹配的位置之前」。但是,你可以做的是用每個正則表達式的執行替換一個單詞(因爲這樣你總是可以在字符串的開頭定位)。所以你想要做的就是運行下面的正則表達式,只要它替換了一些東西。

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

+1中添加了單詞邊界,因爲無法在單個正則表達式中執行。 – 2009-11-03 09:08:39

+0

很好的解釋! – 2009-11-07 21:11:42

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 
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;