置き換える前に追加の一致を許可するには、sedで名前を変更します。

置き換える前に追加の一致を許可するには、sedで名前を変更します。

.txtファイルを使用してfileAのテキスト名を変更しようとしていますsed。 2番目の列はfileA製品名の完全な説明です。商品名を商品IDに変更したいです。ただし、説明の一部のテキストには同様の内容があります(例fileA:)。 「オレンジジュース」は2行と4行に2回現れます。

renamefile製品名をsedsed

ファイルA:

AB12345    100    0    Apple juice 20/05   AB
CD67890    150    0    Orange juice with pulp 22/05   CS
EF25879    100    0    Watermelon juice 19/05   CG
GH96314    98    0    Orange juice 20/05   PU
IJ74123    95    0    Strawberry juice with lemon 17/05   ST

ファイルの名前を変更します。

s/\<Apple juice\>/3071/g
s/\<Orange juice with pulp\>/3072/g
s/\<Orange juice\>/3073/g
s/\<Watermelon juice\>/3074/g
s/\<Apple juice with lemon\>/3075/g
s/\<Strawberry juice with lemon\>/3076/g

現在の出力:

AB12345    100    0    3071 20/05   AB
CD67890    150    0    **3073** 22/05   CS
EF25879    100    0    3074 19/05   CG
GH96314    98    0    3073 20/05   PU
IJ74123    95    0    3076 17/05   ST

希望の出力:

AB12345    100    0    3071 20/05   AB
CD67890    150    0    3072 22/05   CS
EF25879    100    0    3074 19/05   CG
GH96314    98    0    3073 20/05   PU
IJ74123    95    0    3076 17/05   ST

私は正確に一致する場合にのみ交換に役立つことをどこかで見つけたので、「<>」を使用しています。しかし、この場合はうまくいかないようです。 (エラーは現在の出力で太字で表示されます。)

文字列の置き換えでは、最初の2つの文字列が一致した後に、より多くの単語を考慮し、その名前をそのIDに置き換えるより良い効率的な方法がありますか?

十分明確ではない場合は教えてください。ありがとうございます!

答え1

renamefile長さに基づいて並べ替え、長い名前を最初に置き換える必要があります。

awk '{ print length, $0 }' renamefile| sort -nr | cut -d" " -f2- > renamefile2

出力

s/\<Strawberry juice with lemon\>/3076/g
s/\<Orange juice with pulp\>/3072/g
s/\<Apple juice with lemon\>/3075/g
s/\<Watermelon juice\>/3074/g
s/\<Orange juice\>/3073/g
s/\<Apple juice\>/3071/g

それでは問題なく申請できます。

sed -f renamefile2 fileA

説明する:

awkループ行

  • lengthawk に組み込まれた関数です。引数なしで呼び出すと、現在の行のサイズが印刷されます(詳細は奇妙な長さ)
  • $0現在の行

次のコマンドは、行自体の横にある各行の長さを印刷します。

awk '{ print length, $0 }' renamefile

24 s/\<Apple juice\>/3071/g
35 s/\<Orange juice with pulp\>/3072/g
25 s/\<Orange juice\>/3073/g

sort入力したテキストが並べ替えられます。

  • -n数字で並べ替えられます
  • -r結果が下向きになるように反転します。

cutテキストの一部を選択します(最終スクリプトでは長さを必要とせず、行の一部をsed選択するだけです)。

  • -d" "ここに区切り文字を指定しますspace
  • -f2-フィールド2から行末まで

答え2

/製品名の後に常に2桁の数字、1桁の数字、2桁の数字が続く場合は、正規表現で囲み、逆参照を使用してそれ自体に置き換えることができます。

前の 4 つの空白文字を一致させてその文字に置き換えることもできます。

ファイルの名前を変更します。

s/( {4})Apple juice( [[:digit:]]{2}\/[[:digit:]]{2})/\13071\2/
s/( {4})Orange juice with pulp( [[:digit:]]{2}\/[[:digit:]]{2})/\13072\2/
s/( {4})Orange juice( [[:digit:]]{2}\/[[:digit:]]{2})/\13073\2/
s/( {4})Watermelon juice( [[:digit:]]{2}\/[[:digit:]]{2})/\13074\2/
s/( {4})Apple juice with lemon( [[:digit:]]{2}\/[[:digit:]]{2})/\13075\2/
s/( {4})Strawberry juice with lemon( [[:digit:]]{2}\/[[:digit:]]{2})/\13076\2/

出力:

$ sed -Ef renamefile fileA
AB12345    100    0    3071 20/05   AB
CD67890    150    0    3072 22/05   CS
EF25879    100    0    3074 19/05   CG
GH96314    98    0    3073 20/05   PU
IJ74123    95    0    3076 17/05   ST

答え3

awkを使用する方が簡単です。

$ cat tst.awk
BEGIN {
    id = 3071
    map["Apple juice"]                  = id++
    map["Orange juice with pulp"]       = id++
    map["Orange juice"]                 = id++
    map["Watermelon juice"]             = id++
    map["Apple juice with lemon"]       = id++
    map["Strawberry juice with lemon"]  = id++
}
match($0,/^((\S+\s+){3})(.*\S)((\s+\S+){2})/,a) {
    $0 = a[1] map[a[3]] a[4]
    print
}

$ awk -f tst.awk file
AB12345    100    0    3071 20/05   AB
CD67890    150    0    3072 22/05   CS
EF25879    100    0    3074 19/05   CG
GH96314    98    0    3073 20/05   PU
IJ74123    95    0    3076 17/05   ST

\<上記はGNU sedと\>単語の境界を使用しているため、GNU awkを使用しています。

答え4

GNU sedを使用して最初に名前変更ファイルを動的に変更し(手動で編集する必要がないことを意味します)、それをsedコードとしてファイルAで編集します。

名前が変更されたファイルで変更したのは、\>の代わりにRHS境界で改行を見つけることでした。しかし、その前にfileAのパターン空間に改行文字を挿入します。

$ sed -re '
     1i\
s/(\\s+\\S+){2}\\s*$/\\n&/
     s/\\>/\\n/
' renamefile | sed -rf - fileA

出力:

AB12345    100    0    3071 20/05   AB
CD67890    150    0    3072 22/05   CS
EF25879    100    0    3074 19/05   CG
GH96314    98    0    3073 20/05   PU
IJ74123    95    0    3076 17/05   ST

関連情報