ファイル内のすべての単語を読み取り、見つかった場合に別のファイルの代替単語に置き換える方法

ファイル内のすべての単語を読み取り、見つかった場合に別のファイルの代替単語に置き換える方法

一つ一つ読まなければならないフルワードファイルの各行を使用するsedか、awkその単語がファイルにある場合は別のファイルの単語に置き換えます。

A.txtファイルの内容:

1, This is a Record One, Value1, Dummy_val1 One, $$MOON$$
2, This is a Record Two, Value2, Dummy_val2 Two, #LATER
3, This is a Record Three, Value3, Dummy_val3 Three, #LATER
4, This is a Record Four, Value4, Dummy_val4 Four, $$MOON$$

その後、Search_Replace_File.txtは、どの単語をどの単語に置き換えるべきかについての情報を提供します。

One=Ten
Two=Twenty
Three=Thirty
Four=Forty
$$MOON$$=SUN
#LATER=SNOW

予想される出力は次のとおりです。

1, This is a Record Ten, Value1, Dummy_val1 Ten, SUN
2, This is a Record Twenty, Value2, Dummy_val2 Twenty, SNOW
3, This is a Record Thirty, Value3, Dummy_val3 Thirty, SNOW
4, This is a Record Forty, Value4, Dummy_val4 Forty, SUN

メモ:

  1. リスト内の古い単語が新しい単語に置き換えられている場合、新しい単語と他の単語のマッピングがマッピングファイルに存在する場合は、それでも置き換えることができます。
  2. 代替文字列には、以下の記号を含めることもできます。 $$MOON$$=日曜日 #LATER=雪

これまで、次のコードを試しましたが、単語を置き換えません。

#!/bin/bash
while read var
do
search_string=`echo "$var"|awk -F= '{print $1}'`
replace_string=`echo "$var"|awk -F= '{print $2}'`
sed "s/$searchstring/$replacestring/g" fileA.csv > fileB.csv
done < Search_Replace_File.txt

mv fileB.csv fileA.csv

答え1

すべてのUnixシステムのすべてのシェルでawkを使用してください。

$ cat tst.awk
BEGIN { FS="=" }
NR==FNR {
    map[$1] = $2
    next
}
{
    head = ""
    tail = $0
    while ( match(tail,/[^,= ]+/) ) {
        old = substr(tail,RSTART,RLENGTH)
        new = (old in map ? map[old] : old)
        head = head substr(tail,1,RSTART-1) new
        tail = substr(tail,RSTART+RLENGTH)
    }
    print head tail
}

$ awk -f tst.awk Search_Replace_File.txt fileA.txt
1, This is a Record Ten, Value1, Dummy_val1 Ten, SUN
2, This is a Record Twenty, Value2, Dummy_val2 Twenty, SNOW
3, This is a Record Thirty, Value3, Dummy_val3 Thirty, SNOW
4, This is a Record Forty, Value4, Dummy_val4 Forty, SUN

上記の仮定は、入力単語に,=または空白が含まれていないが、他の文字は含まれるということです。

また、古い単語が新しい単語にマッピングされ、その新しい単語が他の新しい単語にもマッピングできる場合、上記のコードはそうしません。これは無限再帰が発生し、最初のマッピングのみが保存されるためです。

答え2

次のように awk を使用してこれを実行できます。

awk '
BEGIN {
  d = "[$]{2}"
  w = "[[:alpha:]][_[:alnum:]]*"
  re = d w d "|" "[#]?" w
}
FS == "="{a[$1]=$2;next}
{
  z = ""
  t = $0
  gsub(re, RS "&" RS, t)
  nf = split(t, x, RS)
  for (i=1; i<=nf; i++)
    z = z ((i%2) ? x[i] : ((x[i] in a) ? a[x[i]] : x[i]))
  print z
}
' FS="=" Search_Replace_File.txt FS=" " fileA.txt
1, This is a  Record Ten, Value1, Dummy_val1 Ten, SUN
2, This is a Record Twenty, Value2, Dummy_val2 Twenty, SNOW
3, This is a Record Thirty, Value3, Dummy_val3 Thirty, SNOW
4, This is a Record Forty, Value4, Dummy_val4 Forty, SUN

  • 単語を定義する正規表現です。
  • 現在の行の単語を改行文字で区切ります。
  • 次に、現在の行を改行文字で除算します。
  • すべての単語は偶数フィールドです。
  • 単語が配列aにあることを確認して置き換えます。
  • 変更された行を印刷します。

答え3

使用幸せ(以前のPerl_6)

~$ raku -pe 'BEGIN my %h = (          \ 
               "One" => "Ten",        \ 
               "Two" => "Twenty",     \
               "Three" => "Thirty",   \
               "Four" => "Forty",     \
               q[$$MOON$$] => "SUN",  \
               q[#LATER] => "SNOW");  \ 
             s:g/ [ ^ | <punct>+ | <blank>+] <( @(%h.keys) )> [ <punct>+ | <blank>+ | $ ] /%h{$/}/;'  file

Perlシリーズのプログラミング言語であるRakuで書かれた答えです。上記は、-pesedに似た自動印刷コマンドラインフラグを使用します。ハッシュは%hインラインで宣言されます。エスケープ$する必要がありますが、上記のように書くこと"\$\$MOON\$\$"ができるので、q[$$MOON$$]バックスラッシュの必要性が減ります。

交換の鍵は、グローバル修飾子をs///使用することです。:g一致ドメイン(左半分)内では、@(%h.keys)ハッシュキーは-sigiled配列にキャストされ、@これは一致ドメイン内のリテラル文字列として理解されます。代替フィールド(右半分)では、一致する変数が、置き換えられた対応するキーを$/回復するために使用されます。value

ここで問題は」性格「通常は英数字のプラス - _(アンダースコア)として定義されます。この場合、左右の単語の境界を表すため、Rakuの<<(左)と>>(右)の幅がゼロの正規表現アンカーを使用します。存在しない場合、同じ内容はFourteen誤って置き換えられますFortyteen(以下の例の入力ファイルの最後の行を参照してください。例の出力は正しい結果を示しています)。

OPが次に開始/終了キーを使用してソリューションを要求したためいいえ -英数字と_文字(したがって幅0の単語境界アンカーの使用を除く)を使用する1つのアプローチは、以下の可能性を説明することです。

s:g/ [ ^ | <punct>+ | <blank>+] <( @(%h.keys) )> [ <punct>+ | <blank>+ | $ ] /%h{$/}/;

入力例:

1, This is a Record One, Value1, Dummy_val1 One, $$MOON$$
2, This is a Record Two, Value2, Dummy_val2 Two, #LATER
3, This is a Record Three, Value3, Dummy_val3 Three, #LATER
4, This is a Record Four, Value4, Dummy_val4 Four, $$MOON$$
5, This is a Record Fourteen, Value14, Dummy_val14 Fourteen, #LATER

出力例:

1, This is a Record Ten, Value1, Dummy_val1 Ten, SUN
2, This is a Record Twenty, Value2, Dummy_val2 Twenty, SNOW
3, This is a Record Thirty, Value3, Dummy_val3 Thirty, SNOW
4, This is a Record Forty, Value4, Dummy_val4 Forty, SUN
5, This is a Record Fourteen, Value14, Dummy_val14 Fourteen, SNOW

おそらくより良い(より安定した)アプローチは、より慎重に選択することです。いいえ -単語キー(例:次に開始/終了することを確認)いいえ -単語文字(例:#LATER#代わりに#LATER)。その後、使用二つハッシュ値は次のとおりです。

~$ raku -pe 'BEGIN    my %words = ("One" => "Ten", "Two" => "Twenty", "Three" => "Thirty", "Four" => "Forty")  \
             andthen  my %non-words = (q[$$MOON$$] => "SUN", q[#LATER#] => "SNOW");  \
             s:g/ << @(%words.keys) >> /%words{$/}/;  \
             s:g/ [ ^ | <punct>+ | <blank>+] <( @(%non-words.keys) )> [ <punct>+ | <blank>+ | $ ] /%non-words{$/}/;'  file

このコードは、同じサンプル入力ファイル(#LATERで更新#LATER#)を使用して上記と同じサンプル出力を生成します。

https://docs.raku.org/言語/regexes#Regex_interpolation
https://docs.raku.org/言語/regexes
https://docs.raku.org
https://raku.org

関連情報