【问题标题】:How to capitalize first letter of every word using sed in OSX如何在 OSX 中使用 sed 将每个单词的首字母大写
【发布时间】:2015-08-12 14:56:33
【问题描述】:

我正在尝试使用以下 sed 命令将字符串中每个单词的首字母大写,但它不起作用:

 echo "my string" | sed 's/\b\(.\)/\u\1/g'

输出:

 my string

我做错了什么?

谢谢

【问题讨论】:

标签: macos bash sed pipe capitalization


【解决方案1】:

鉴于您的示例输入,这将适用于任何 awk:

$ echo 'my string' | awk '{for (i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) substr($i,2)} 1'
My String

如果这不能满足您的需求,请编辑您的问题以显示一些更具代表性的示例输入和预期输出。

【讨论】:

    【解决方案2】:

    这是一个适用于 OSX 的 sed 解决方案:

    echo 'my string
    ANOTHER STRING
    tHiRd StRiNg' | sed -En '
    y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
    :loop
    h
    s/^(.*[^a-zA-Z0-9])?([a-z]).*$/\2/
    t next
    b end
    :next
    y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
    G
    s/^(.+)\n(.*[^a-zA-Z0-9])?[a-z](.*)$/\2\1\3/
    t loop
    :end
    p
    '
    
    Output:
    My String
    Another String
    Third String
    

    sed 命令的工作原理如下:

    1. sed 输入一行,第一个 y 命令将所有大写字母转换为小写。
    2. 从 :loop 到 t 循环的命令形成一个循环,执行一次 for 当前行中的每个单词,每个单词的首字母大写。
    3. 当当前行没有更多要大写的单词时,p 命令打印该行,sed 输入下一行。

    以下是循环的工作原理:

    1. h 命令将当前行保存到保持状态 空间。
    2. 第一个 s 命令查找第一个的第一个字母 非大写单词。如果找到这样的单词,s 命令保存 它的第一个字母到模式空间,并且 t 命令分支到 :next 标签。如果没有找到这样的词,说明 没有更多要大写的单词,执行 b 命令 相反,分支到 :end 标签以打印并完成 当前行的处理。
    3. 如果找到需要大写的单词,则在 :next 标签,y 命令将现在位于模式空间中的第一个字母从小写转换为大写。
    4. G 命令附加当前的未转换版本 从保持空间到模式空间末尾的线。
    5. 第二个 s 命令重构当前行,将当前正在处理的单词的第一个字母替换为其大写版本。
    6. t 命令分支到 :loop 标签以查找下一个单词 需要大写。

    执行速度测试表明,当前 sed 方法的执行速度与 Ed Morton 提交的 awk 解决方案大致相同。

    【讨论】:

      【解决方案3】:

      这个问题已经解决了:Uppercasing First Letter of Words Using SED

      我在 GNU sed 上得到了正确的行为,但在 OS X 附带的标准 BSD sed 上却没有。我认为 \u “正则表达式”是 GNU 的东西。 “port install gsed”怎么样?

      编辑:如果您真的想使用 BSD sed,我不推荐(因为命令变得非常难看),那么您可以执行以下操作: sed -E "s:([^[:alnum:]_]|^)a:\1A:g; s:([^[:alnum:]_]|^)b:\1B:g; s:([^[:alnum:]_]|^)c:\1C:g; s:([^[:alnum:]_]|^)d:\1D:g; s:([^[:alnum:]_]|^)e:\1E:g; s:([^[:alnum:]_]|^)f:\1F:g; s:([^[:alnum:]_]|^)g:\1G:g; s:([^[:alnum:]_]|^)h:\1H:g; s:([^[:alnum:]_]|^)i:\1I:g; s:([^[:alnum:]_]|^)j:\1J:g; s:([^[:alnum:]_]|^)k:\1K:g; s:([^[:alnum:]_]|^)l:\1L:g; s:([^[:alnum:]_]|^)m:\1M:g; s:([^[:alnum:]_]|^)n:\1N:g; s:([^[:alnum:]_]|^)o:\1O:g; s:([^[:alnum:]_]|^)p:\1P:g; s:([^[:alnum:]_]|^)q:\1Q:g; s:([^[:alnum:]_]|^)r:\1R:g; s:([^[:alnum:]_]|^)s:\1S:g; s:([^[:alnum:]_]|^)t:\1T:g; s:([^[:alnum:]_]|^)u:\1U:g; s:([^[:alnum:]_]|^)v:\1V:g; s:([^[:alnum:]_]|^)w:\1W:g; s:([^[:alnum:]_]|^)x:\1X:g; s:([^[:alnum:]_]|^)y:\1Y:g; s:([^[:alnum:]_]|^)z:\1Z:g;"

      【讨论】:

      • 不幸的是,安装 gsed 不是一个可行的选择。我正在编写一个主要由其他 OSX 用户使用的脚本。
      • 那么我认为 sed 不是适合这里工作的工具,因为如果没有 GNU 扩展,您将无法使用大写字母,例如,您可能想尝试 perl(不了解 awk)。如果你真的需要用 BSD sed 来做,那么你必须一个字母一个字母地做...
      • 我也得出了同样的结论。我最终使用了 bash for loop 和 tr。
      • @Ares 每次你在 shell 中编写一个循环只是为了操作文本你都有错误的方法(谷歌它)。只需使用 awk,因为文本操作是它的发明目的。
      【解决方案4】:

      试试:

      echo "my string" | sed -r 's/\b(.)/\u\1/g'
      

      【讨论】:

      • 我在 OSX 上运行它。我收到“sed:非法选项 -- r”
      • 在 OSX 上使用 -E(我猜)
      • sed: 1: "s/\b(.)/\u\1/g": \1 未在 RE 中定义
      • 它可能无法在 OSX 中运行(未经测试),但它在 Bash on Mint 中运行得非常好。谢谢,这正是我要找的。​​span>
      猜你喜欢
      • 2014-11-15
      • 2010-12-05
      • 2015-11-10
      • 1970-01-01
      • 1970-01-01
      • 2021-08-08
      • 2020-08-30
      • 2015-11-04
      • 2012-11-11
      相关资源
      最近更新 更多