awk 对 gsub 不区分大小写

Sol*_*osa 1 awk text-processing case-sensitivity

我有"|"分隔的文本数据,并且想要转换列值

$ cat infile
Mark|father
Jason|SOn
Jose|son
Steffy|daugHter
Run Code Online (Sandbox Code Playgroud)

我想不敏感地搜索 (father|son|daughter) 大小写并将任何情况下的父亲替换为父亲,将任何情况下的儿子替换为儿子,将任何情况下的女儿替换为女儿

所以输出文件应该是这样的

$ cat outfile
Mark Father
Jason Son
Jose Son
Steffy Daughter
Run Code Online (Sandbox Code Playgroud)

我正在尝试 IGNORECASE 与 sub 或 gsub 的不同组合,但它会按 infile 中的原样打印所有条目

Sté*_*las 5

这是试图回答问题的原始版本。自那以后,要求发生了变化。

这是 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
Run Code Online (Sandbox Code Playgroud)

regexp 匹配这 3 个单词中的任何一个,但前提是它们之前或之后都没有非空格。

\L将整个单词转为小写,\u只有第一个字符转为大写(那些来自70 年代的ex/ vi,但不幸的是没有达到标准sed)。

相同的方法可以使用perl -pe而不是sed -E(使其可能perl比 GNU更可移植,因为更多的系统具有比 GNU更大的系统sed),尽管perl您可以将其简化为:

perl -pe 's/(?<!\S)(son|daughter|father)(?!\S)/\L\u$&/i'
Run Code Online (Sandbox Code Playgroud)

也就是说,使用否定环顾运算符来确保这些字符串不是较长的以空格分隔的单词的一部分(例如Jason在您的输入中)。另请参阅\binperl\<, \>in sed 中的单词边界运算符,但这些运算符更像(?!\w)是将grand-son 变为grand-Son 的运算符,因为-它不是单词组成字符。

那些每行最多只替换一次。要替换所有匹配项,您可以将g标志添加到perl上面的标志。将它添加到sed一个可能会错过一些,因为在 a 上Mark son SON sOn,第一个匹配项将替换" son "" Son ",然后sed将继续搜索"SON sOn",因此不会找到\sbefore的匹配项SON。这可以通过预先将所有空白字符加倍并在之后恢复来解决:

sed -E 's/\s/&&/g
        s/(^|\s)(son|daughter|father)(\s|$)/\1\L\u\2\3/ig
        s/(\s)\1/\1/g'
Run Code Online (Sandbox Code Playgroud)

虽然这开始有点太复杂了。