【问题标题】:linux bash, camel case string to separate by dashlinux bash,驼峰式字符串用破折号分隔
【发布时间】:2012-01-20 03:19:51
【问题描述】:

有没有办法像这样转换:

MyDirectoryFileLine

my-directory-file-line

我找到了一些将所有字母转换为大写或小写的方法,但不是那种方式;有什么想法吗?

【问题讨论】:

标签: linux bash camelcasing


【解决方案1】:

您可以使用s/\([A-Z]\)/-\L\1/g 查找大写字母并将其替换为破折号并且它是小写字母。但是,这会在行的开头给您一个破折号,因此您需要另一个 sed 表达式来处理它。

这应该可行:

sed --expression 's/\([A-Z]\)/-\L\1/g' \
    --expression 's/^-//'              \
    <<< "MyDirectoryFileLine"

【讨论】:

  • 我用过类似的东西:tmp2=echo ${tmp[@],} | sed -e 's/\([A-Z]\)/-\L\1/g'
  • 无法在 OS X 上开箱即用 - 请参阅 @4ndrew 的版本以了解也适用于 OS X 的解决方案。
  • 对于 OS X 使用:sed -e 's/\([A-Z]\)/-\1/g' -e 's/^-//' &lt;&lt;&lt; "MyDirectoryFileLine" - 基本上从 sed 替换中删除 \L
  • 留下领先的-,例如-my-var-name。执行额外的 sed pass 以删除。
【解决方案2】:

我建议使用 sed 来做到这一点:

NEW=$(echo MyDirectoryFileLine        \
     | sed 's/\(.\)\([A-Z]\)/\1-\2/g' \
     | tr '[:upper:]' '[:lower:]')

UPD我忘记转换为小写,更新代码

【讨论】:

  • 您“建议使用 awk”,但在您的答案中使用 sed?
  • 这太棒了,因为它也适用于 OS X sed,无需安装 gnu 版本。
【解决方案3】:
echo MyDirectoryFileLine | perl -ne 'print lc(join("-", split(/(?=[A-Z])/)))'

打印my-directory-file-line

【讨论】:

  • 很好,但是 perl 是不是有点矫枉过正?
  • 现在调用 Perl 并没有真正使用 Bash,是吗?
【解决方案4】:

@bilalq 的回答略有不同,涵盖了一些更可能的边缘情况:

echo "MyDirectoryMVPFileLine"                          \
| sed 's/\([^A-Z]\)\([A-Z0-9]\)/\1-\2/g'               \
| sed 's/\([A-Z0-9]\)\([A-Z0-9]\)\([^A-Z]\)/\1-\2\3/g' \
| tr '[:upper:]' '[:lower:]'

输出还是:

my-directory-mvp-file-line

还有:

WhatADeal -> what-a-deal
TheMVP -> the-mvp
DoSomeABTesting -> do-some-ab-testing
The3rdThing -> the-3rd-thing
The3Things -> the-3-things
ThingNumber3 -> thing-number-3

【讨论】:

    【解决方案5】:

    此处发布的解决方案均不适合我。大多数都不能很好地支持多个平台。来自@4ndrew 的那个很接近,但它在多个大写字符相邻的边缘情况下失败了(例如:FooMVPClient 变成foo-mv-pclient 而不是foo-mvp-client)。

    这对我有用:

    echo "MyDirectoryMVPFileLine"              \
    | sed 's/\([a-z]\)\([A-Z]\)/\1-\2/g'       \
    | sed 's/\([A-Z]\{2,\}\)\([A-Z]\)/\1-\2/g' \
    | tr '[:upper:]' '[:lower:]'
    

    输出:

    my-directory-mvp-file-line
    

    【讨论】:

      【解决方案6】:

      我的微薄贡献与“/”一起使用(可能用于目录名称或 github 存储库名称)。它不像它可能的那样干净,但可以完成工作。我以@Peter 的贡献为基础,然后进行了一些调整。

      function kebab_case() {
        echo -n "$1" |\
        sed 's/\([^A-Z+]\)\([A-Z0-9]\)/\1-\2/g' |\
        sed 's/\([0-9]\)\([A-Z]\)/\1-\2/g' |\
        sed 's/\([A-Z]\)\([0-9]\)/\1-\2/g' |\
        sed 's/--/-/g' |\
        sed 's/\([\/]\)-/\1/g' |\
        tr '[:upper:]' '[:lower:]'
      }
      
      function assert_kebab_equal() {
          local Actual
          local Expected
          Expected="$1"
          Actual="$(kebab_case "$2")"
      
          if [ "${Expected}" != "${Actual}" ]; then
            echo Error:
            echo "  Actual: ${Actual}"
            echo "Expected: ${Expected}"
          else
            echo "$2" "$1" | awk '{ printf "%-30s -> %-40s\n", $1, $2}'
          fi
      }
      
      assert_kebab_equal "abc-def" "AbcDef"
      assert_kebab_equal "/abc-def-ghi/def" "/AbcDef-Ghi/Def"
      assert_kebab_equal "/ab-cd-ef" "/AbCdEf"
      assert_kebab_equal "repo-owner/repo-name" "RepoOwner/RepoName"
      assert_kebab_equal "repo-12-owner/repo-12-name" "Repo12Owner/Repo12Name"
      assert_kebab_equal "repo-12-3-owner/repo-12-name" "Repo12-3Owner/Repo12Name"
      assert_kebab_equal "repo-owner/repo-name" "REPO-OWNER/REPO-NAME"
      assert_kebab_equal "repo-owner-2/repo-name" "REPO-OWNER2/REPO-NAME"
      assert_kebab_equal "repo-1-owner" "REPO1-OWNER"
      assert_kebab_equal "repo-1-owner-1/22-repo-2-name" "REPO1-OWNER1/22REPO-2NAME"
      
      
      # Outputs:
      
      AbcDef                         -> abc-def                                 
      /AbcDef-Ghi/Def                -> /abc-def-ghi/def                        
      /AbCdEf                        -> /ab-cd-ef                               
      RepoOwner/RepoName             -> repo-owner/repo-name                    
      Repo12Owner/Repo12Name         -> repo-12-owner/repo-12-name              
      Repo12-3Owner/Repo12Name       -> repo-12-3-owner/repo-12-name            
      REPO-OWNER/REPO-NAME           -> repo-owner/repo-name                    
      REPO-OWNER2/REPO-NAME          -> repo-owner-2/repo-name                  
      REPO1-OWNER                    -> repo-1-owner                            
      REPO1-OWNER1/22REPO-2NAME      -> repo-1-owner-1/22-repo-2-name         
      
      

      【讨论】:

        【解决方案7】:

        这可能对你有用:

        <<<"MyDirectoryFileLine" sed 's/[A-Z]/-\l&/g;s/.//'
        my-directory-file-line
        

        【讨论】:

          【解决方案8】:

          使用 GNU sed:

          echo "MyDirectoryFileLine"|sed -e 's/\([A-Z]\)/-\L\1/g'
          

          如果你觉得麻烦,你只需要去掉第一个破折号:

          echo "MyDirectoryFileLine"|sed -e 's/\([A-Z]\)/-\L\1/g' -e 's/^-//'
          

          使用 BSD sed 会更长一些:

          echo "MyDirectoryFileLine"|sed -e 's/\([A-Z]\)/-\1/g' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' -e 's/^-//'
          

          更新:BSD 版本可以与 GNU 版本兼容,所以我推荐使用后者。

          【讨论】:

            【解决方案9】:
            echo "SomeACRONYMInCamelCaseString" \
             | sed -e 's/\([a-z]\)\([A-Z]\)/\1-\L\2/' \
             | sed -e 's/\(.*\)/\L\1/')
            

            sed -e 's/\([a-z]\)\([A-Z]\)/\1-\L\2/' 用连字符和小写字母替换大写字母,前提是它前面有一个小写字母。 sed -e 's/\(.*\)/\L\1/' 将整个字符串小写

            【讨论】:

              猜你喜欢
              • 2012-05-12
              • 2015-07-07
              • 2018-05-29
              • 1970-01-01
              • 2010-11-08
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多