【问题标题】:How to convert to title case a specific column如何将特定列转换为标题大小写
【发布时间】:2021-10-15 19:19:37
【问题描述】:

我想出了这个代码:

cut -d';' -f4 columns.csv | sed 's/.*/\L&/; s/[a-z]*/\u&/g'

它实际上完成了第四列的工作,但是我失去了其他列..

我尝试过没有成功:

cut -d';' -f4 columns.csv | sed -i 's/.*/\L&/; s/[a-z]*/\u&/g'

那么,我如何将更改应用到文件中的特定列并保持其他列不变?

假设 columns.csv 的内容是:

TEXT;more text;SoMe MoRe TeXt;THE FOURTH COLUMN;something else

那么,预期的输出应该是:

TEXT;more text;SoMe MoRe TeXt;The Fourth Column;something else

【问题讨论】:

  • 列中除了字母、数字和空格之外还能有其他字符吗?
  • 是的,破折号、括号和圆点:( - . )

标签: linux shell awk sed


【解决方案1】:

不是简单的awk,但应该可以工作:

awk -F";" '{t=split($4,a," ");$4="";for(i=1;i<=t;i++) {a[i]=substr(a[i],1,1) tolower(substr(a[i],2));$4=$4 sprintf("%s ",a[i])}$4=substr($4,1,length($4)-1)}1' OFS=";" file
TEXT;more text;SoMe MoRe TeXt;The Fourth Column;something else

一些较短的版本

awk -F";" '{t=split($4,a," ");$4="";for(i=1;i<=t;i++) {a[i]=substr(a[i],1,1) tolower(substr(a[i],2));$4=$4 a[i](t==i?"":" ")}}1' OFS=";" file

【讨论】:

  • 谢谢,你真好!
【解决方案2】:

perl:

$ perl -F';' -lane '$F[3] =~ s/[a-z]+/\L\u$&/gi; print join ";", @F' columns.csv
TEXT;more text;SoMe MoRe TeXt;The Fourth Column;something else
  • -F';'使用;分割输入行
  • $F[3] =~ s/[a-z]+/\L\u$&amp;/gi 仅更改第 4 列的大小写
  • print join ";", @F打印修改后的字段

Unicode 版本:

perl -Mopen=locale -Mutf8 -F';' -lane '$F[3]=~s/\p{L}+/\L\u$&/gi;
                                       print join ";", @F'

【讨论】:

  • 谢谢,实际上将 -i 添加到这个 perl 命令中,我可以就地进行更改。太好了!!
  • @AndrésChandía 我也添加了 unicode 版本,看看是否有帮助
  • 谢谢,确实有帮助!!
【解决方案3】:

GNU sed:

sed -ri 's/;/&\r/3;:1;s/\r([^; ]+\s*)/\L\u\1\r/;t1;s/\r//' columns.csv

更新:

sed -i 's/; */&\n/3;:1;s/\n\([^; ]\+ *\)/\L\u\1\n/;t1;s/\n//' columns.csv

将锚点\r (\n) 放在字段 4 的开头。我们编辑整个单词并将锚点移动到下一个单词的开头。只要substitution 命令中的模式匹配,就会执行标签t1 :1 的跳转。移除锚点。

【讨论】:

  • 更好的是,在以前的 perl 脚本中,我遇到了一些非 ascii 字符(如 À、Ç 等)的问题,这个 sed 命令解决了这个问题......也感谢您,以及其他人的出色表现救命!!!
  • 我们不知道输入不能包含\rs,因此添加作为锚点的字符不是一个好的选择。您应该使用 \n 代替,因为它不能出现在输入中,因为 sed 一次读取文件一个 \n 分隔的字符串。您应该提到-r\s 需要GNU sed(也许还有其他东西?)。
  • @EdMorton,而不是\r,可以选择\a\f,从未想过\n,谢谢
  • 该文件也可以包含\a\f,所以\n确实是最好的选择。
  • 为什么不明确引用第四个字段,即s/[^;]*/\n&amp;/4
【解决方案4】:

在每个 Unix 机器上的任何 shell 中使用任何 awk:

$ cat tst.awk
BEGIN { FS=OFS=";" }
{
    title = ""
    numWords = split($4,words,/ /)
    for (wordNr=1; wordNr<=numWords; wordNr++) {
        word = words[wordNr]
        word = toupper(substr(word,1,1)) tolower(substr(word,2))
        title = (wordNr>1 ? title " " : "") word
    }
    $4 = title
    print
}

$ awk -f tst.awk file
TEXT;more text;SoMe MoRe TeXt;The Fourth Column;something else

不过,标题中的真正大写要复杂得多。

【讨论】:

  • 几乎是我帖子的精确副本 :)
  • @Jotne 是的,当我看到你的文章时,我想过不发布这个,但我不喜欢你的东西(例如,在每个单词后添加一个空格,然后在末尾删除它而不是只是没有在最后一个单词后添加空格,在循环的每次迭代中修改 $4,在 2 个不同的地方将 FS 和 OFS 设置为相同的值,多​​个单字母变量)并且它没有创建中点 word如果需要,我认为也值得发布我的,用于增强更完整标题转换的变量(例如,不转换“A”或“of”,除非在行首)。
  • @Jotne 我在查看问题时的 SOP 是先尝试回答,然后阅读任何现有答案,如果有一个足够接近或比我想出的答案更好,那么我不会发布我的。在这种情况下,鉴于与您的相似,我本可以采取任何一种方式发布我的,但出于我刚才提到的原因决定这样做。
【解决方案5】:

这可能对你有用(GNU sed):

sed -E 's/[^;]*/\n&\n/4;h;s/\S*/\L\u&/g;H;g;s/\n.*\n(.*)\n.*\n(.*)\n.*/\2\1/' file

用换行符分隔第四个字段并复制。

每个单词的第一个字符大写。

将修改后的行附加到原始行。

使用模式匹配,将原来的第四个字段替换为修改后的字段。

【讨论】:

    猜你喜欢
    • 2022-01-03
    • 2021-10-13
    • 1970-01-01
    • 1970-01-01
    • 2012-11-27
    • 2010-11-15
    相关资源
    最近更新 更多