awk 對 gsub 不區分大小寫
我已經
"|"
分隔了文本數據,並且想要轉換列值$ cat infile Mark|father Jason|SOn Jose|son Steffy|daugHter
我想不區分大小寫地搜尋 (father|son|daughter) 並將任何情況下的父親替換為父親,任何情況下的兒子替換為兒子,任何情況下的女兒替換為女兒
所以outfile應該是這樣的
$ cat outfile Mark Father Jason Son Jose Son Steffy Daughter
我正在嘗試 IGNORECASE 與 sub 或 gsub 的不同組合,但它會按 infile 中的方式列印所有條目
我會使用雜湊查找而不是正則表達式比較和 *sub() 來提高效率和穩健性(如果您決定使用包含正則表達式元字元或反向引用的字元串,或者可以是其他字元串的子字元串):
$ cat tst.awk BEGIN { FS = "|" split("Father|Son|Daughter",tmp) for (i in tmp) { map[tolower(tmp[i])] = tmp[i] } } { lc = tolower($2) } lc in map { $2 = map[lc] } { print }
$ awk -f tst.awk file Mark Father Jason Son Jose Son Steffy Daughter
這是嘗試回答問題的原始版本。從那以後,要求發生了變化。
這是 GNU 實現
sed
擅長的一件事:$ sed -E 's/(^|\s)(son|daughter|father)(\s|$)/\1\L\u\2\3/i' < file Mark Father Jason Son Jose Son Steffy Daughter
正則表達式匹配這 3 個單詞中的任何一個,但前提是它們既沒有前後也沒有非空格。
\L
將整個單詞變成小寫,\u
只有第一個字元變成大寫(那些來自ex
/vi
來自 70 年代,但不幸的是沒有達到標準sed
)。這同樣適用於
perl -pe
代替sed -E
(使其可能perl
比 GNU更多的系統更可移植sed
),但perl
您可以將其簡化為:perl -pe 's/(?<!\S)(son|daughter|father)(?!\S)/\L\u$&/i'
也就是說,使用否定的環視運算符來確保這些字元串不是較長的以空格分隔的單詞的一部分(例如
Jason
在您的輸入中)。另請參見\b
inperl
和\<
,\>
in sed ,單詞邊界運算符,但這些運算符更像(?!\w)
是會將 grand-son 轉換為 grand-Son 例如,因為-
它不是單片語成字元。那些只替換每行最多一次。要替換所有出現,您可以將
g
標誌添加到perl
上面的標誌。將其添加到sed
其中可能會錯過一些,例如 aMark son SON sOn
,第一個匹配項將替換" son "
為" Son "
,然後sed
將繼續搜尋"SON sOn"
,因此找不到\s
before的匹配項SON
。這可以通過事先將所有空白字元加倍並在之後恢復來解決:sed -E 's/\s/&&/g s/(^|\s)(son|daughter|father)(\s|$)/\1\L\u\2\3/ig s/(\s)\1/\1/g'
雖然這開始有點太複雜了。