Skip to content

JavaScript中的大小写转换

不同的编程语言和框架对于变量、函数和类的命名有不同的约定。将字符串转换为不同的命名法通常是必要的,这就是本指南的用途。

单词边界识别

在将字符串转换为不同的命名法之前,我们需要能够识别单词之间的边界。虽然一种朴素的方法可以依赖于空格或其他分隔符来分隔单词,但这种方法不足以处理所有情况。正则表达式提供了一个更强大的解决方案。经过多次尝试,我发现以下正则表达式是最强大的:

const r = /[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g;

即使对我来说,这看起来也很吓人。让我们将其分解为其组成部分:

  • [A-Z]{2,} 匹配两个或更多连续的大写字母。这对于识别像 XMLHTML 这样的缩写词很有用。
  • (?=[A-Z][a-z]+[0-9]*|\b) 是一个前瞻断言,用于匹配单词边界。
  • [A-Z]?[a-z]+[0-9]* 匹配以可选的大写字母开头,后跟一个或多个小写字母和零个或多个数字的单词。
  • [A-Z] 匹配一个大写字母。
  • [0-9]+ 匹配一个或多个数字。
  • g 是一个全局标志,允许正则表达式在字符串中匹配所有出现。

将任何命名法转换为驼峰命名法

驼峰命名法要求每个单词的首字母大写,除了第一个单词。例如 someName 是驼峰命名法,但 SomeName 不是。这种约定在JavaScript中用于变量、函数和类的命名。

为了将字符串转换为驼峰命名法,我们需要:

  • 使用String.prototype.match()方法使用适当的正则表达式将字符串拆分为单词。
  • 使用Array.prototype.map()方法转换每个单词。使用String.prototype.slice()String.prototype.toUpperCase()方法将每个单词的第一个字母大写,使用String.prototype.toLowerCase()方法将其余部分转换为小写。
  • 使用Array.prototype.join()方法将单词组合成一个字符串。
  • 最后,使用String.prototype.toLowerCase()方法将最终字符串的第一个字母转换为小写。
const toCamelCase = str => {
  const s =
    str &&
    str
      .match(
        /[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g
      )
      .map(x => x.slice(0, 1).toUpperCase() + x.slice(1).toLowerCase())
      .join('');
  return s.slice(0, 1).toLowerCase() + s.slice(1);
};

toCamelCase('some_database_field_name'); // 'someDatabaseFieldName'
toCamelCase('Some label that needs to be camelized');
// 'someLabelThatNeedsToBeCamelized'
toCamelCase('some-javascript-property'); // 'someJavascriptProperty'
toCamelCase('some-mixed_string with spaces_underscores-and-hyphens');
// 'someMixedStringWithSpacesUnderscoresAndHyphens'

将任何大小写转换为帕斯卡命名法

帕斯卡命名法通常用于面向对象的语言,如Java或C#。帕斯卡命名法字符串的每个单词的第一个字母都大写。例如,SomeName是帕斯卡命名法,但someName不是。

将字符串转换为帕斯卡命名法的过程与将字符串转换为驼峰命名法的过程非常相似。唯一的区别是我们不需要将最终字符串的第一个字母转换为小写。

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

toPascalCase('some_database_field_name'); // 'SomeDatabaseFieldName'
toPascalCase('Some label that needs to be pascalized');
// 'SomeLabelThatNeedsToBePascalized'
toPascalCase('some-javascript-property'); // 'SomeJavascriptProperty'
toPascalCase('some-mixed_string with spaces_underscores-and-hyphens');
// 'SomeMixedStringWithSpacesUnderscoresAndHyphens'

将任何大小写转换为烤串命名法

烤串命名法通常用于URL的片段。烤串命名法字符串是全部小写,单词之间用连字符分隔。例如,some-name是烤串命名法,但some-Name不是。

为了将字符串转换为kebab case(短横线连接的小写字符串),我们只需要将每个单词转换为小写,并用短横线连接起来。

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

toKebabCase('camelCase'); // 'camel-case'
toKebabCase('some text'); // 'some-text'
toKebabCase('some-mixed_string With spaces_underscores-and-hyphens');
// 'some-mixed-string-with-spaces-underscores-and-hyphens'
toKebabCase('AllThe-small Things'); // 'all-the-small-things'
toKebabCase('IAmEditingSomeXMLAndHTML');
// 'i-am-editing-some-xml-and-html'

将任何大小写转换为snake case

Snake case通常用于Python或Ruby等语言。Snake case字符串是全部小写,单词之间用下划线分隔。例如,some_name是snake case,但some_Name不是。

将字符串转换为snake case的过程与转换为kebab case的过程相同,只是将短横线替换为下划线。

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

toSnakeCase('camelCase'); // 'camel_case'
toSnakeCase('some text'); // 'some_text'
toSnakeCase('some-mixed_string With spaces_underscores-and-hyphens');
// 'some_mixed_string_with_spaces_underscores_and_hyphens'
toSnakeCase('AllThe-small Things'); // 'all_the_small_things'
toSnakeCase('IAmEditingSomeXMLAndHTML');
// 'i_am_editing_some_xml_and_html'

将任何大小写转换为title case

Title case通常用于标题或标题。Title case字符串的每个单词的首字母大写,单词之间用空格分隔。例如,Some Name是title case,但Some name不是。

转换过程与Pascal case相同,只是分隔符由空字符串变为空格。

const toTitleCase = str =>
  str
    .match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
    .map(x => x.slice(0, 1).toUpperCase() + x.slice(1))
    .join(' ');

toTitleCase('some_database_field_name'); // 'Some Database Field Name'
toTitleCase('Some label that needs to be title-cased');
// 'Some Label That Needs To Be Title Cased'
toTitleCase('some-package-name'); // 'Some Package Name'
toTitleCase('some-mixed_string with spaces_underscores-and-hyphens');
// 'Some Mixed String With Spaces Underscores And Hyphens'

将任何大小写转换为句首大写

最后,句首大写通常用于句子中。句首大写的字符串以首字母大写,单词之间用空格分隔。例如,Some name是句首大写,但some Name不是。

由于句首大写比较宽松,我们只需要确保分隔符是空格,并且字符串的第一个字母大写。

const toSentenceCase = str => {
  const s =
    str &&
    str
      .match(
        /[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g
      )
      .join(' ');
  return s.slice(0, 1).toUpperCase() + s.slice(1);
};

toSentenceCase('some_database_field_name'); // 'Some database field name'
toSentenceCase('Some label that needs to be title-cased');
// 'Some label that needs to be title cased'
toSentenceCase('some-package-name'); // 'Some package name'
toSentenceCase('some-mixed_string with spaces_underscores-and-hyphens');
// 'Some mixed string with spaces underscores and hyphens'

转换为任何大小写

我们刚刚浏览了很多代码片段,您可能需要在项目中使用多个。让我们看看是否可以将它们合并到一个函数中,该函数期望一个大小写作为参数,并返回转换后的字符串。

const convertCase = (str, toCase = 'camel') => {
  if (!str) return '';

  const delimiter =
    toCase === 'snake'
      ? '_'
      : toCase === 'kebab'
        ? '-'
        : ['title', 'sentence'].includes(toCase)
          ? ' '
          : '';

  const transform = ['camel', 'pascal'].includes(toCase)
    ? x => x.slice(0, 1).toUpperCase() + x.slice(1).toLowerCase()
    : ['snake', 'kebab'].includes(toCase)
      ? x => x.toLowerCase()
      : toCase === 'title'
        ? x => x.slice(0, 1).toUpperCase() + x.slice(1)
        : x => x;

  const finalTransform =
    toCase === 'camel'
      ? x => x.slice(0, 1).toLowerCase() + x.slice(1)
      : toCase === 'sentence'
        ? x => x.slice(0, 1).toUpperCase() + x.slice(1)
        : x => x;

  const words = str.match(
    /[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g
  );

  return finalTransform(words.map(transform).join(delimiter));
};

convertCase('mixed_string with spaces_underscores-and-hyphens', 'camel');
// 'mixedStringWithSpacesUnderscoresAndHyphens'
convertCase('mixed_string with spaces_underscores-and-hyphens', 'pascal');
// 'MixedStringWithSpacesUnderscoresAndHyphens'
convertCase('mixed_string with spaces_underscores-and-hyphens', 'kebab');
// 'mixed-string-with-spaces-underscores-and-hyphens'
convertCase('mixed_string with spaces_underscores-and-hyphens', 'snake');
// 'mixed_string_with_spaces_underscores_and_hyphens'
convertCase('mixed_string with spaces_underscores-and-hyphens', 'title');
// 'Mixed String With Spaces Underscores And Hyphens'
convertCase('mixed_string with spaces_underscores-and-hyphens', 'sentence');
// 'Mixed string with spaces underscores and hyphens'

虽然这段代码确实很复杂,但它是在之前所有代码片段的基础上构建的,根据所需的大小写情况有条件地应用适当的转换。由于许多代码片段具有相似性,条件尽可能地被压缩,以避免重复。