2015-03-03 81 views
0

我想根據文件$ key中定義的「字符串串」對替換文本。Grep在Perl替換(RHS)內

採樣輸入文件$輸入

a b c foo 
d e f moo 
g h i boo 

預定義的 「鑰匙」 文件$關鍵

cow moo 
code foo 
ghost boo 
cheer woo 

所需的輸出

a b c code 
d e f cow 
g h i ghost 

我ATTE MPT

perl -pe 's/(.*?)(\woo)/$1qq{grep -oP ".*(?=\s$2)" $key}/e' $input > $output 

錯誤返回

syntax error at -e line 1, near "$1qq{grep -oP ".*(?=\s$2)" $key}" 
syntax error at -e line 1, near "s/(.*?)(\woo)/$1qq{grep -oP ".*(?=\s$2)" $key}/ee" 

任何幫助,將不勝感激。

建議更好的方法,以達到預期的效果是非常歡迎的,但一個公認的答案會非常包括用perl substition溶液或評論。

回答

4

使用命令行的perl,

perl -lane' 
    BEGIN{ local @ARGV = pop; %h = reverse map split, <> } 
    print join " ", @F[0..2], $h{$F[3]}; 

' input key 

輸出

a b c code 
d e f cow 
g h i ghost 

更新

perl -lane' 
    BEGIN{ local @ARGV = pop; %h = reverse map /(.+)\s+(\S+)$/, <> } 
    print join " ", @F[0..2], $h{$F[3]}; 

' input key 
+0

尼斯簡潔的解決方案,謝謝你的貢獻。我很想知道如果關鍵文件行是'zyx code foo'等,並且所需的輸出行是'abczyx code'等(輸入行與'abc foo'等相同),你將如何適應 – okapiho 2015-03-07 11:16:02

+0

@okapiho檢查更新。 – 2015-03-08 08:23:11

3

下面是如何,您可以使用awk

awk 'FNR==NR {a[$2]=$1;next} $NF=a[$NF]' key input 
a b c code 
d e f cow 
g h i ghost 

它讀取key文件陣列a
然後使用數組a鍵來更改最後一個字段打印input文件。

如果a[$NF]可以是0,使用:

awk 'FNR==NR {a[$2]=$1;next} {$NF=a[$NF];print}' key input 
+0

如果'a [$ NF]'在數值上評估爲零,那麼將會失敗。 +1爲正確的做法。 – 2015-03-03 22:02:13

3
$1qq{grep -oP ".*(?=\s$2)" $key} 

不是有效的Perl表達式。也許你的意思是

$1 . qq{grep -oP ".*(?=\s$2)" $key} 

雖然在表達式中還有許多其他的錯誤。 (你用qq{}你應該使用qx{},你忘了跳過\,你用$key而沒有給它賦值,也許更多。)

維護的解決方案,只有讀取密鑰文件一次:

perl -e' 
    my %lookup; 
    open(my $fh, "<", shift(@ARGV)) 
     or die $!; 

    while (<$fh>) { 
     my ($v,$k) = split; 
     $lookup{$k} = $v; 
    } 

    while (<>) { 
     my @f = split; 

     next if [email protected]; # Skip blank lines. 

     if (defined($lookup{$f[3]})) { 
     warn("Can'\''t find key \"$f[3]\". Copying record unchanged.\n"); 
     print; 
     next; 
     } 

     $f[3] = $lookup{$f[3]}; 
     print("@f\n"); 
    } 
' keyfile.txt input.txt >output.txt 
+0

做'$ 1。 qx {grep -oP「。*(?= \ s $ 2)」$ key}'在這種情況下工作嗎?有了這個(你)的更正,在我的機器上我得到一個錯誤,如果我沒有弄錯,這個過程不會退出(沒有新的提示,必須^ c)。錯誤:無法識別的轉義字符在-e行1處傳遞。 'name「main :: key」或字符串在-e行1,<>行1. – okapiho 2015-03-03 14:28:03

+0

@okapiho,我沒有檢查你是否犯了其他錯誤,但事實證明你有。你也忘了逃避'\',並且你從來沒有給'$ key'賦值。可能還有更多。 – ikegami 2015-03-03 14:33:55

+0

出於某種原因(我的技能水平以外),對我來說,你的'die'在第14行打印'找不到\ n而不是'找不到$ f [3] \ n'。否則,它的工作效果很好,我很容易理解你的代碼,根據我的需要調整它,並且在perldoc.perl.org/perlintro.html的幫助下學習了很多東西,謝謝:) – okapiho 2015-03-07 11:26:31

2

個人 - 我不喜歡做一個套,因爲他們難以閱讀。

的模式替換一般的訣竅是這樣的:

my %replacements; 
open (my $keyfile, "<", "key_file.txt") or die $!; 
while ($keyfile) { 
    chomp; 
    my ($value, $key) = split; 
    $replacements{$key} = $value; 
} 

my $regex = join ("\b|\b", keys %replacements); 
$regex = qr/$regex/; 

open (my $replace_fh, "<", "input_file") or die $!; 
while (<$replace_fh>) { 
    s/\b($regex)\b/$replacements{$1}/g; 
    print; 
} 

果然您輸入替代的哈希,構建在它匹配任何一個字正則表達式,然後使用該正則表達式「匹配」 - 使用$1散列查找鍵。

+0

你能否澄清你的意思是「看起來你的鑰匙在你的例子中被顛倒了」?我在我的示例 – okapiho 2015-03-03 14:33:21

+0

@okapiho中沒有看到我的意思,他表示關鍵字段通常是第一個字段('鍵值')。輸入中列的順序是不尋常的('value key'),但沒有錯。我已經修復了他的代碼。 – ikegami 2015-03-03 14:36:38

+0

@okapiho,注意:Sobrique的代碼替換了輸入的所有列中的值,而不僅僅是第四個。 – ikegami 2015-03-03 14:39:07