用awk改变字符串的大小写

时间:2013-01-03 13:14:12

标签: regex unix awk

我是个新手,所以请耐心等待。

目标是更改字符串的大小写,使每个单词的第一个字母为大写,其余字母为小写。 (为了使示例简单,“word”在此定义为严格的字母字符;所有其他字符都被视为分隔符。)

我学会了一种很好的方法,使用以下awk命令从本网站的另一篇文章中将每个单词的第一个字母大写:

echo 'abce efgh ijkl mnop' | awk '{for (i=1;i <= NF;i++) {sub(".",substr(toupper($i),1,1),$i)} print}' - &gt; Abcd Efgh Ijkl Mnop

通过在awk命令前加上tr命令:

,可以轻松完成剩下的小写字母

echo 'aBcD EfGh ijkl MNOP' | tr [A-Z] [a-z] | awk '{for (i=1;i <= NF;i++) {sub(".",substr(toupper($i),1,1),$i)} print}' - &gt; Abcd Efgh Ijkl Mnop

然而,为了更多地了解awk,我想用一个类似的awk结构将除了第一个字母以外的所有字母改为小写。我使用正则表达式\B[A-Za-z]+来匹配单词的所有字母但是第一个,并使用awk命令substr(tolower($i),2)以小写字母提供相同的字母,如下所示:

echo 'ABCD EFGH IJKL MNOP' | awk '{for (i=1;i <= NF;i++) {sub("\B[A-Za-z]+",substr(tolower($i),2),$i)} print}' - &gt; Abcd EFGH IJKL MNOP

请注意,第一个单词正确转换,但其余单词保持不变。我将非常感谢解释为什么剩下的单词没有正确转换以及如何让它们这样做。

4 个答案:

答案 0 :(得分:8)

问题是,\B(零宽度非单词边界)似乎只在行的开头匹配,因此$1可以正常工作但$2以及后续字段不起作用匹配正则表达式,因此它们不会被替换并保持大写。不确定为什么\B不匹配,除了第一个字段... B应匹配任何单词中的任何位置:

echo 'ABCD EFGH IJKL MNOP' | awk '{for (i=1; i<=NF; ++i) { print match($i, /\B/); }}'
2   # \B matches ABCD at 2nd character as expected
0   # no match for EFGH
0   # no match for IJKL
0   # no match for MNOP

无论如何要实现你的结果(只将该行的第一个字符大写),你可以在$0(整行)上操作,而不是使用for循环:

echo 'ABCD EFGH IJKL MNOP' | awk '{print toupper(substr($0,1,1)) tolower(substr($0,2)) }'

或者,如果您仍希望单独使用每个单词,但只使用awk

awk '{for (i=1; i<=NF; ++i) { $i=toupper(substr($i,1,1)) tolower(substr($i,2)); } print }'

答案 1 :(得分:4)

使用sub()函数或其他函数(如gsub()等)匹配正则表达式时,最好使用以下格式:

sub(/regex/, replacement, target)

这与你所拥有的不同:

sub("regex", replacement, target)

所以你的命令变为:

awk '{ for (i=1;i<=NF;i++) sub(/\B\w+/, substr(tolower($i),2), $i) }1'

结果:

Abcd Efgh Ijkl Mnop

关于String Functions的这篇文章也许值得一读。 HTH。


我应该说有更简单的方法可以达到你想要的效果,例如使用GNU sed

sed -r 's/\B\w+/\L&/g'

答案 2 :(得分:2)

我的解决方案是获取sub的第一部分,并使用你的正则表达式的第一个substr

echo 'ABCD EFGH IJKL MNOP' | awk '{for (i=1 ; i <= NF ; i++) {sub(substr($i,2),tolower(substr($i,2)),$i)} print }'
Abcd Efgh Ijkl Mnop

答案 3 :(得分:1)

您必须在\ B

之前添加另一个\字符
 echo 'ABCD EFGH IJKL MNOP' | awk '{for (i=1;i <= NF;i++)
 {sub("\\B[A-Za-z]+",substr(tolower($i),2),$i)} print}'

只有\ B awk给了我这个警告:

  

awk:cmd。 line:1:warning:转义序列\B' treated as plain B'