文字列の置換に正規表現とAWKを使用する方法は?

文字列の置換に正規表現とAWKを使用する方法は?

ファイルにテキストがあるとします。

(bookmarks
("Chapter 1 Introduction 1" "#1"
("1.1 Problem Statement and Basic Definitions 23" "#2")
("Exercises 31" "#30")
("Notes and References 42" "#34"))
)

"各数字に11を追加し、ある場合は各行に1を追加したいと思います。

(bookmarks
("Chapter 1 Introduction 12" "#12"
("1.1 Problem Statement and Basic Definitions 34" "#13")
("Exercises 42" "#41")
("Notes and References 53" "#45"))
)

GNU AWKと正規表現を使用したソリューションは次のとおりです。

awk -F'#' 'NF>1{gsub(/"(\d+)\""/, "\1+11\"")}'

(\d+)\"つまり、 で置き換えたいと思います\1+10\"\1ここでグループは で表されます(\d+)。しかし、これはうまくいきません。どのように動作させることができますか?

gawkが最善の解決策でない場合は、何を使用できますか?

ベストアンサー1

これを試してみてください(遅いが必要です)。

awk '{a=gensub(/.*#([0-9]+)(\").*/,"\\1","g",$0);if(a~/[0-9]+/) {gsub(/[0-9]+\"/,a+11"\"",$0);}print $0}' YourFile

テストあなたの例を見てください:

kent$  echo '(bookmarks
("Chapter 1 Introduction 1" "#1"
("1.1 Problem Statement and Basic Definitions 2" "#2")
("Exercises 30" "#30")
("Notes and References 34" "#34"))
)
'|awk '{a=gensub(/.*#([0-9]+)(\").*/,"\\1","g",$0);if(a~/[0-9]+/) {gsub(/[0-9]+\"/,a+11"\"",$0);}print $0}'   
(bookmarks
("Chapter 1 Introduction 12" "#12"
("1.1 Problem Statement and Basic Definitions 13" "#13")
("Exercises 41" "#41")
("Notes and References 45" "#45"))
)

2 つの数字 (例: 1" と "#1") が異なる場合、またはパターンの同じ行に数字が多い場合 (例: 23"...32"..."#123") 行に注意してください。


修正する

@Tim(OP)は、同じ行の後続の数字が"異なる可能性があると述べたので、以前の解決策をいくつか変更して新しい例で機能するようにしました。

ところで、この例ではディレクトリ構造のようで、2つの数字の違いが何なのか理解できません。最初のページは印刷されたページ番号で、2番目の番号はページインデックスです。私は正しいですか?

何が起こっても、あなたの要件はあなたが最もよく知っています。それでもgawkを使用する新しいソリューションです(読みやすくするためにコマンドを複数行に分割しました)。

awk 'BEGIN{FS=OFS="\" \"#"}{if(NF<2){print;next;}
        a=gensub(/.* ([0-9]+)$/,"\\1","g",$1);
        b=gensub(/([0-9]+)\"/,"\\1","g",$2); 
        gsub(/[0-9]+$/,a+11,$1);
        gsub(/^[0-9]+/,b+11,$2);
        print $1,$2
}' yourFile

テストそしてあなたのもの新しい例:

kent$  echo '(bookmarks
("Chapter 1 Introduction 1" "#1"
("1.1 Problem Statement and Basic Definitions 23" "#2")
("Exercises 31" "#30")
("Notes and References 42" "#34"))
)
'|awk 'BEGIN{FS=OFS="\" \"#"}{if(NF<2){print;next;}
        a=gensub(/.* ([0-9]+)$/,"\\1","g",$1);
        b=gensub(/([0-9]+)\"/,"\\1","g",$2); 
        gsub(/[0-9]+$/,a+11,$1);
        gsub(/^[0-9]+/,b+11,$2);
        print $1,$2
}'                        
(bookmarks
("Chapter 1 Introduction 12" "#12"
("1.1 Problem Statement and Basic Definitions 34" "#13")
("Exercises 42" "#41")
("Notes and References 53" "#45"))
)


編集2@Timのコメントに基づいて

(1) FS=OFS="\" \"#" は、入力と出力のフィールド区切り文字が二重引用符、空白、二重引用符、および # であることを意味しますか。なぜ二重引用符を2回指定するのですか?

入力部分と出力部分の両方の区切り文字が正確です。区切り文字を次のように定義します。

" "#

2つの二重引用符があります(例入力に基づいて)。

(2)/.*([0-9]+)$/, $ は文字列の終わりを表しますか?

まさに!

(3)gensub()の3番目のパラメータの「g」と「G」の違いは何ですか? Gとgの間に違いはありません。これを見てください:

gensub(regexp, replacement, how [, target]) #
    Search the target string target for matches of the regular expression regexp. 
    If "how" is a string beginning with ‘g’ or ‘G’ (short for “global”), then 
        replace all matches of regexp with replacement.

これはから来たものですhttp://www.gnu.org/s/gawk/manual/html_node/String-Functions.html。 gensubの詳細な使い方を読むことができます。

おすすめ記事