将下划线转换为 PascalCase,即 UpperCamelCase

use*_*541 32 shell-script

如果我有一个看起来像这样的字符串:

"this_is_the_string"
Run Code Online (Sandbox Code Playgroud)

在 bash 脚本中,我想将其转换为 PascalCase,即 UpperCamelCase,如下所示:

"ThisIsTheString"
Run Code Online (Sandbox Code Playgroud)

我发现可以像这样转换为lowerCamelCase:

"this_is_the_string" | sed -r 's/([a-z]+)_([a-z])([a-z]+)/\1\U\2\L\3/'
Run Code Online (Sandbox Code Playgroud)

不幸的是,我对正则表达式不够熟悉,无法修改它。

Jan*_*nis 50

$ echo "this_is_the_string" | sed -r 's/(^|_)([a-z])/\U\2/g'            
ThisIsTheString
Run Code Online (Sandbox Code Playgroud)


(^|_)在字符串的开头或下划线之后替换模式- 第一组
([a-z])单个小写字母 - 第二组
通过全局
\U\2大写第二组
g

  • 如何使用非 GNU sed 实现此目的? (7认同)
  • 注意:`\U` 是 POSIX 的 GNU 扩展。 (4认同)
  • 请注意,您也应该捕获数字`sed -r 's/(^|[-_ ]+)([0-9a-z])/\U\2/g'`。所以像 *"this_is_2nd_string"* 这样的字符串也能工作。 (2认同)
  • 在 Mac 上无法正常工作 ~$ bash --version GNU bash,版本 3.2.57(1)-release (x86_64-apple-darwin21) 版权所有 (C) 2007 Free Software Foundation, Inc. ~$ ~$ echo "this_is_the_string" | sed -r 's/(^|_)([az])/\U\2/g' UthisUisUtheUstring (2认同)

don*_*sti 12

由于您使用的是bash,如果您将字符串存储在变量中,您也可以仅在 shell 中进行:

uscore="this_is_the_string_to_be_converted"
arr=(${uscore//_/ })
printf %s "${arr[@]^}"
ThisIsTheStringToBeConverted
Run Code Online (Sandbox Code Playgroud)

${uscore//_/ }_用空格替换全部,(....)将字符串拆分为数组,${arr[@]^}将每个元素的第一个字母转换为大写,然后printf %s ..一个接一个地打印所有元素。
您可以将驼峰式字符串存储到另一个变量中:

printf -v ccase %s "${arr[@]^}"
Run Code Online (Sandbox Code Playgroud)

并在以后使用/重用它,例如:

printf %s\\n $ccase
ThisIsTheStringToBeConverted
Run Code Online (Sandbox Code Playgroud)

或者,使用zsh

uscore="this_is_the_string_to_be_converted"
arr=(${(s:_:)uscore})
printf %s "${(C)arr}"
ThisIsTheStringToBeConverted
Run Code Online (Sandbox Code Playgroud)

(${(s:_:)uscore})将字符串拆分_为一个数组,(C)将每个元素的第一个字母大写,并printf %s ...一个接一个地打印所有元素..
要将其存储在另一个变量中,您可以(j::)用来连接元素:

ccase=${(j::)${(C)arr}}
Run Code Online (Sandbox Code Playgroud)

并在以后使用/重用它:

printf %s\\n $ccase
ThisIsTheStringToBeConverted
Run Code Online (Sandbox Code Playgroud)


ter*_*don 10

这是一种 Perl 方式:

$ echo "this_is_the_string" | perl -pe 's/(^|_)./uc($&)/ge;s/_//g'
ThisIsTheString
Run Code Online (Sandbox Code Playgroud)

它可以处理任意长度的字符串:

$ echo "here_is_another_larger_string_with_more_parts" | 
    perl -pe 's/(^|_)./uc($&)/ge;s/_//g'
HereIsAnotherLargerStringWithMoreParts
Run Code Online (Sandbox Code Playgroud)

它将匹配.出现在字符串开头或下划线 ( (^|_))之后的任何字符 ( )并将其替换为自身的大写版本 ( uc($&))。这$&是一个特殊的变量,包含刚刚匹配的任何内容。该e在的端s///ge允许使用表达式(该uc()取代内在这种情况下函数)和g使得它替换所有出现在的行。第二个替换删除下划线。


mya*_*aut 6

没有必要在正则表达式匹配中表示整个字符串——sed 有一个/g修饰符,允许你遍历多个匹配并替换它们中的每一个:

echo "this_is_the_string" | sed 's/_\([a-z]\)/\U\1/g;s/^\([a-z]\)/\U\1/g'
Run Code Online (Sandbox Code Playgroud)

第一个正则表达式是_\([a-z]\)-- 下划线后的每个字母;第二个匹配字符串中的第一个字母。


ctr*_*lor 6

我之所以输入这个答案,是因为它比迄今为止的任何其他答案都更短、更简单。

sed -re "s~(^|_)(.)~\U\2~g"
Run Code Online (Sandbox Code Playgroud)

_它表示:大写,a或开头后面的字符。非字母不会被改变,因为它们没有大小写。

  • (续)... (3) 我认为问题的实质是转换字符串,以便用下划线(`_`)表示的断词改为通过大小写转换来表示,这一点已经很清楚了。鉴于此,“FOO_BAR”→“FOOBAR”显然是错误的(因为它丢弃了分词信息),尽管“FOO_BAR”→“FooBar”可能是正确的。(4) 同样,导致冲突的映射似乎与问题的精神相悖。例如,我认为将“DO_SPORTS”和“DOS_PORTS”转换为同一目标的答案是错误的。 (2认同)