regex - 用awk更改字符串的大小写

标签 regex unix awk

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

目的是更改字符串的大小写,以使每个单词的首字母大写,其余字母小写。 (为使示例简单,此处将“单词”严格定义为字母字符;所有其他字符均视为分隔符。)

我使用以下awk命令从该网站上的另一篇文章中学习了一种使每个单词的首字母大写的好方法:
echo 'abce efgh ijkl mnop' | awk '{for (i=1;i <= NF;i++) {sub(".",substr(toupper($i),1,1),$i)} print}'-> 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}'-> 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}'-> Abcd EFGH IJKL MNOP

请注意,第一个单词已正确转换,但其余单词保持不变。我非常感谢您解释为什么其余的单词不能正确转换以及如何使它们转换。

最佳答案

问题在于\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 }'

关于regex - 用awk更改字符串的大小写,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14139672/

相关文章:

java - 模式优化

unix - Unix 中什么生成 "text file busy"消息?

unix - execlp() 系统调用如何工作?

awk - 为什么在 Awk 中未定义用于连接的表达式的求值顺序?

shell - awk 不检查语句是否正确它在输出中显示所有打印行

javascript - 为什么 HTML5 checkValidity() 返回的结果与 JavaScript regexp.test() 不同?

.net - 正则表达式解析任意深度的函数

java - 正则表达式 - 解析字符串

linux - 通过读取命令在 POSIX 兼容的 shell 脚本中解析 cal 输出

awk - 如何使用awk打印值之间的引号