驼峰命名法转短横线命名法

28

我有一个kebabize函数,可以将camelCase转换为kebab-case。这是我的代码。它能否更加优化?我知道可以使用正则表达式来解决这个问题。但是,我想在不使用正则表达式的情况下完成。

我有一个kebabize功能,可以将camelCase转换为kebab-case。我分享我的代码。它是否可以更优化?我知道可以使用正则表达式来解决此问题。但是,我希望在不使用正则表达式的情况下完成。

const kebabize = str => {

    let subs = []
    let char = ''
    let j = 0

    for( let i = 0; i < str.length; i++ ) {

        char = str[i]

        if(str[i] === char.toUpperCase()) {
            subs.push(str.slice(j, i))
            j = i
        }

        if(i == str.length - 1) {
            subs.push(str.slice(j, str.length))
        }
    }

    return subs.map(el => (el.charAt(0).toLowerCase() + el.substr(1, el.length))).join('-')
}

kebabize('myNameIsStack')

1
与其优化你的代码,我真的建议你使用一个库来处理这种类型的实用函数。例如,使用 Lodash 中的 _.kebabCase 函数! - Jacob van Lingen
1
@YevgenGorbunkov 我只是在提高我的逻辑技能,所以不使用正则表达式。我知道这种方法更清晰和优化。 - Stack
7个回答

48

我有一个与Marc相似的一行代码,但使用更简单的正则表达式,根据我的基准测试速度提高了约20%(Chrome 89)。

const kebabize = (str) => str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, ($, ofs) => (ofs ? "-" : "") + $.toLowerCase())

const words = ['StackOverflow', 'camelCase', 'alllowercase', 'ALLCAPITALLETTERS', 'CustomXMLParser', 'APIFinder', 'JSONResponseData', 'Person20Address', 'UserAPI20Endpoint'];

console.log(words.map(kebabize));

[A-Z]+(?![a-z])匹配任何连续的大写字母,不包括后跟小写字母(表示下一个单词)的任何大写字母。添加|[A-Z]然后包括任何单个大写字母。它必须放在连续大写表达式之后,否则表达式将单独匹配所有大写字母,并且永远不会匹配连续大写字母。

String.prototype.replace可以使用替换函数。这里,对于每个单词,它返回匹配的大写字母变为小写,如果匹配偏移量是真值(不为零-不是字符串的第一个字符),则在前缀中加入连字符。

我怀疑Marc的解决方案比我的效率低,因为通过使用replace插入连字符并在整个字符串小写化之后,它必须多次迭代字符串,而且它的表达式也具有更复杂的前瞻/后瞻构造。

基准测试


不确定是否有其他人期望这样,但 -F 将变成 --f - karizma

31

const kebabize = str => {
   return str.split('').map((letter, idx) => {
     return letter.toUpperCase() === letter
      ? `${idx !== 0 ? '-' : ''}${letter.toLowerCase()}`
      : letter;
   }).join('');
}

console.log(kebabize('myNameIsStack'));
console.log(kebabize('MyNameIsStack'));

你可以检查每个字母是否是大写,然后进行替换。

2
只有输入字符串为camelCase而不是UpperCamelCase时,此代码才能正常工作。 - Vinay Mahamuni
3
“@VinayMahamuni,UpperCamelCase是PascalCase的一种形式,顺便提一下,它们并不完全相同。” - Maxie Berkmann
3
str.split("")在处理由多个部分组成的Unicode符号时会给出意外的结果。请使用[...str]Array.from(str)代替。 - theberzi

14

5
这在全大写单词中会失败。JSONResponseData将返回jsonresponse-data而不是json-response-data。我想这可能是一种风格选择,但这不是大多数人所期望的,如果他们不知道这会导致问题。 - ABabin
@ABabin,但是jsonRespondeData而不是JSONResponseData会更正确吧? - NNL993
2
@NNL993 没有“正确”的标准。有些人在camelCase中大写缩写词 - 有时是到一定长度或有选择性地或始终如此。这里的其他解决方案可以处理这些情况,而不会增加太多额外开销。 - ABabin

9

以下是我的解决方案:

适用于camelCase和PascalCase:

let words = ['StackOverflow', 'camelCase', 'alllowercase', 'ALLCAPITALLETTERS', 'CustomXMLParser', 'APIFinder', 'JSONResponseData', 'Person20Address', 'UserAPI20Endpoint'];

let result = words.map(w => w.replace(/((?<=[a-z\d])[A-Z]|(?<=[A-Z\d])[A-Z](?=[a-z]))/g, '-$1').toLowerCase());

console.log(result);

/*

Returns:
[
  "stack-overflow",
  "camel-case",
  "alllowercase",
  "allcapitalletters",
  "custom-xml-parser",
  "api-finder",
  "json-response-data",
  "person20-address",
  "user-api20-endpoint"
]

*/

说明:

  1. 匹配以下正则表达式之一:
  • 查找任何大写字母,其直接前面是小写字母或数字,或
  • 查找任何大写字母,其直接前面是大写字母或数字,且紧随其后的是小写字母
  1. 用破折号('-')和捕获的大写字母替换匹配位置
  2. 最后将整个字符串转换为小写。

在Safari上无法工作。 - Niels Prins

3

I would use something like this.

function kebabize(string) {
  // uppercase after a non-uppercase or uppercase before non-uppercase
  const upper = /(?<!\p{Uppercase_Letter})\p{Uppercase_Letter}|\p{Uppercase_Letter}(?!\p{Uppercase_Letter})/gu;
  return string.replace(upper, "-$&").replace(/^-/, "").toLowerCase();
}


const strings = ["myNameIsStack", "HTTPRequestData", "DataX", "Foo6HelloWorld9Bar", "Áb"];
const result  = strings.map(kebabize);

console.log(result);

此代码片段将所有非大写字符前或后的大写字符替换为-,然后删除字符串开头处(如果有的话)的-,并将整个字符串转换为小写。


1
请注意这个解决方案,Safari会失败,因为Safari尚不支持负回顾前置。 - lowzhao

0

这是我想出来的解决方案:

let resultDiv = document.querySelector(".result");

let camelCase = "thisIsCamelCase";
let kebabCase;
kebabCase = camelCase.split('').map(el=> {
  const charCode = el.charCodeAt(0);
  if(charCode>=65 && charCode<=90){
    return "-" + el.toLowerCase() 
  }else{
    return el;
  }
})

return(kebabCase.join(''))

使用map()提供的索引并删除charCode怎么样? kebabCase = camelCase.split('').map((el,index)=> { if(camelCase.charCodeAt(index)>=65 && camelCase.charCodeAt(index)<=90){ return "-" + el.toLowerCase() }else{ return el; } }) - Rohan Kumar Thakur

0

旧浏览器的简单解决方案:

var str = 'someExampleString'
var i

function camelToKebab() {
  var __str = arguments[0]
  var __result = ''

  for (i = 0; i < __str.length; i++) {
    var x = __str[i]

    if(x === x.toUpperCase()) {
      __result += '-' + x.toLowerCase()
    } else {
      __result += x
    }
  }

  return __result
}

console.log(str, '->', camelToKebab(str))


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接