【问题标题】:Regular rxpression to convert a camel case string into kebab case将骆驼大小写字符串转换为烤肉大小写的正则表达式
【发布时间】:2016-01-30 00:00:14
【问题描述】:
function hyphenate(str) {

  var replace = "-";
  str = str.toLowerCase().replace(/[\s_\b]/g, replace);

  console.log(str);
  return str;
}

hyphenate("This Is Hyphenate"); // this-is-hyphenate
hyphenate("camelCaseString");   // camel-case-string

我正在尝试让我的代码生成第二个函数调用的结果,但尚未确定可以执行此操作的模式。任何帮助将不胜感激。

【问题讨论】:

    标签: javascript regex camelcasing


    【解决方案1】:

    请注意,[\s_\b] 中的 \b 表示退格字符。不确定你真的需要这个。

    使用 ECMAScript 2018 中引入的后向功能更新答案

    const re = /[\W_]+|(?<=[a-z0-9])(?=[A-Z])/g;
    const strs = ['camelCaseString','This      Is Hyphenate','This_Should_Hyphenate', '09Report'];
    strs.forEach(str => 
      console.log( str.replace(re, "-").toLowerCase() )
    );

    [\W_]+|(?&lt;=[a-z0-9])(?=[A-Z]) 正则表达式将匹配

    • [\W_]+ - 任何 1+ 个非单词和 _ 字符
    • | - 或
    • (?&lt;=[a-z0-9])(?=[A-Z]) - 小写 ASCII 字母/数字和大写 ASCII 字母之间的位置。

    旧答案

    我会使用一些不同的逻辑:在单词中的每个大写字母之前添加一个连字符,然后替换并变成小写:

    var re = /[\s_]+|([a-z0-9])(?=[A-Z])/g; 
    var str = 'camelCaseString<br/>This      Is Hyphenate<br/>This_Should_Hyphenate';
    var result = str.replace(re, "$1-").toLowerCase();
    document.body.innerHTML += result;

    说明:

    • [\s_]+ - 一个或多个空格或下划线
    • | - 或者...
    • ([a-z0-9]) - (第 1 组)小写字母或数字(因为 \B 不允许我们匹配 _ 之后的大写字母,如果您想在每个大写字母之前添加 -,请添加 A-Z)李>
    • (?=[A-Z]) - 对大写 ASCII 字母的测试(未使用,因为它 (?=[A-Z]) 是前瞻,零宽度断言)。

    【讨论】:

    • 抱歉,我之前的意思是我将如何处理像“This_Should_Hyphenate”这样的格式
    • _ 的问题在于它被认为是一个单词字符。我添加了一个修复程序。
    • 非常感谢。你给了我一些很好的线索,让我了解更多关于正则表达式模式的信息。我非常感谢它,因为我正在尽可能多地学习。所以本质上,前瞻 ([a-z0-9])(?=[A-Z]) 匹配 ([a-z0-9]) 只有在它后面跟着一个大写字母?我希望我能正确理解这个逻辑。 "$1-" 是否会在前瞻匹配后放置一个连字符?
    • @brndng 1) 是的,只有紧跟其后有一个大写字母。 2) - 将插入到 整体匹配 值之后,并且不会将前瞻匹配值添加到该值,因为它的行为是非消耗,它不会添加它的匹配到整体匹配值并且不推进正则表达式索引。
    【解决方案2】:

    在小写之前尝试先行:

    function hyphenate(str) {
      return str.split(/[\s_\b]|(?=[A-Z])/).join('-').toLowerCase();
    }
    

    【讨论】:

    • 这是一个非常优雅的答案,我需要对前瞻进行一些研究。
    【解决方案3】:

    您可以使用捕获组获取小写后跟大写字母,然后将整个字符串转换为小写:

    str.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase();
    

    【讨论】:

      【解决方案4】:

      这可能超出了您的要求,但希望这个答案能帮助任何试图将(几乎)任何字符串转换为烤肉串的人:

      const convertStringToKebebCase = str => str && str
        .match(/[0-9]{1,}(?=\b)|[A-Z]{2,}(?=[A-Z][a-z]+|[0-9]|\b|_)|[A-Z]?[a-z]+|[A-Z]|[0-9]+/g)
        .map(x => x.toLowerCase())
        .join('-')
      

      这里是上述函数的测试,因此您可以了解它的行为方式(我将函数重命名为 toKebeb 只是为了在此处更容易阅读):

      // Lowercase
      expect(toKebeb('path')).toEqual('path')
      expect(toKebeb('PATH')).toEqual('path')
      
      // Spaces
      expect(toKebeb('path route')).toEqual('path-route')
      expect(toKebeb('path route 0')).toEqual('path-route-0')
      expect(toKebeb('123 path 4 route 567')).toEqual('123-path-4-route-567')
      
      // Kebab
      expect(toKebeb('path-route')).toEqual('path-route')
      expect(toKebeb('PATH-ROUTE')).toEqual('path-route')
      expect(toKebeb('path-route0')).toEqual('path-route-0')
      expect(toKebeb('path-route-0')).toEqual('path-route-0')
      expect(toKebeb('123-path-4-route-567')).toEqual('123-path-4-route-567')
      expect(toKebeb('123-path-4-route-567')).toEqual('123-path-4-route-567')
      
      // Snake
      expect(toKebeb('path_route')).toEqual('path-route')
      expect(toKebeb('PATH_ROUTE')).toEqual('path-route')
      expect(toKebeb('path_route0')).toEqual('path-route-0')
      expect(toKebeb('path_route_0')).toEqual('path-route-0')
      expect(toKebeb('123_path_4_route_567')).toEqual('123-path-4-route-567')
      expect(toKebeb('123_path_4_route_567')).toEqual('123-path-4-route-567')
      
      // Camel
      expect(toKebeb('pathRoute')).toEqual('path-route')
      expect(toKebeb('pathROUTE')).toEqual('path-route')
      expect(toKebeb('pathRoute0')).toEqual('path-route-0')
      expect(toKebeb('pathROUTE0')).toEqual('path-route-0')
      expect(toKebeb('123path4Route567')).toEqual('123-path-4-route-567')
      expect(toKebeb('123path4ROUTE567')).toEqual('123-path-4-route-567')
      expect(toKebeb('pathRouteA')).toEqual('path-route-a')
      expect(toKebeb('pathRouteABC')).toEqual('path-route-abc')
      expect(toKebeb('pathIsARoute')).toEqual('path-is-a-route')
      
      // Other
      expect(toKebeb('path-route0')).toEqual('path-route-0')
      expect(toKebeb('path-route123')).toEqual('path-route-123')
      expect(toKebeb('path1route')).toEqual('path-1-route')
      expect(toKebeb('path123route')).toEqual('path-123-route')
      expect(toKebeb('123pathRoute')).toEqual('123-path-route')
      expect(toKebeb('123PATHRoute')).toEqual('123-path-route')
      expect(toKebeb('123pathROUTE')).toEqual('123-path-route')
      

      我提到这个函数几乎转换任何字符串,这是因为处理数字的方式可能因每个用例而异。例如,期望3dPrinter 返回3d-printer 是完全合理的。可以调整正则表达式以支持这一点,但它会引发其他问题,例如如何处理3dPrinter12my3dPrinterse7en(即尊重哪些数字字符串顺序组合)。支持此类规则将大大增加所需的测试数量,并且总会有例外。

      要支持3dPrinter 示例,您可以将[0-9]{1,}[a-z]{1,}(?=[A-Z]+)| 添加到正则表达式的开头(“/”之后),但这会破坏之前的一些规则。

      要了解此正则表达式的工作原理,请查看regexr 上的模式。

      【讨论】:

        猜你喜欢
        • 2014-10-30
        • 1970-01-01
        • 2014-02-04
        • 2019-05-15
        • 1970-01-01
        • 2011-06-21
        • 1970-01-01
        • 1970-01-01
        • 2010-12-03
        相关资源
        最近更新 更多