🐪

(?=)って何なん?(camelCase,snake_case)

2022/10/25に公開

はじめに

正規表現を勉強していると,意味は分かったけど,

という疑問が解消されないこともあると思います.

ので,

今回は,(?=)という正規表現について,

と感じられるように実践形式で説明していこうと思います.

camelCase→snake_case

ということで,「キャメルケース(camelCase)スネークケース(snake_case)に変換する関数」を一緒に作成していきましょう.

関数の初期状態は以下のようになっています.

transform.js
function transform(str) {
  return str;
}

console.log(transform("camelCase"));

この段階では引数の文字列をそのまま返しているだけなので,コンソールは以下のような表示になります.

console
camelCase

ここから,正規表現をうまく使ってスネークケースに変換していきます.
方針としては,大文字になっている部分を識別して,そこを基準に文字列を分割したのち,分割したそれぞれの要素を_で連結し,最後に全て小文字に変換してあげればよさそうです.


変換の方針

分割にはsplitメソッド,連結にはjoinメソッド,小文字化にはtoLowerCaseメソッドが使えます.また,英語の大文字を識別するのは[A-Z]という正規表現です.

transform.js
function transform(str) {
  return str
+   .split(/[A-Z]/)
+   .join("_")
+   .toLowerCase()
}

console.log(transform("camelCase"));

こんな感じでよさそうです.
さっそくコンソールを確認してみましょう.

console
camel_ase

うん,いい感じ...ではありませんね.camel_caseと表示させたいところcamel_aseになってしまっています.
つまり,Cが消えてしまっていますね.原因を探ってみましょう.

まず,.split(/[A-Z]/)を実行した直後の状態をコンソールで表示させてみます.

transform.js
function transform(str) {
  return str
    .split(/[A-Z]/)
-   .join("_")
-   .toLowerCase()
}

console.log(transform("camelCase"));
console
[ 'camel', 'ase' ]

なるほど,この段階ですでにCが消えてしまっていますね.ということは,.split(/[A-Z]/)では,正規表現に一致した英語の大文字が消されるということみたいです.

ので,

正規表現に一致した英語の大文字が消えないようにしたいですね.

以下のように使っていきます.

transform.js
function transform(str) {
  return str
-   .split(/[A-Z]/)
+   .split(/(?=[A-Z])/)
}

console.log(transform("camelCase"));
console
[ 'camel', 'Case' ]

Cが消えずに残ってくれました.

これより,transform関数は以下のように書くことが出来ます.

transform.js
function transform(str) {
  return str
    .split(/(?=[A-Z])/)
+   .join("_")
+   .toLowerCase()
}

console.log(transform("camelCase"));
console
camel_case

(?=)って何なん

ここで,なぜこれで上手くいくのかを理解するために,「先読み」という概念を理解する必要があります.

先読みとは,次にその正規表現が来る位置へのマッチを表しています.

つまり,
/[A-Z]/は,大文字の英字にマッチしていたのに対し,
/(?=[A-Z])/は,次に大文字の英字が来る位置にマッチしていました.

この違いにより,.split(/(?=[A-Z])/)で上手く分割することが出来ていたのです.

この先読みは,この他にも様々な用途があり,「後読み」や「肯定/否定」など様々なバリエーションがあります.

こちらについては,以下の記事がとても分かりやすかったです.
https://zenn.dev/usamik26/articles/regex-lookahead

snake_case→camelCase

ちなみに,副産物的に「スネークケース(snake_case)をキャメルケース(camelCase)に変換する関数」もできたので載せておきます.


変換の方針

transform.js
String.prototype.capitalize = function() {
  return this[0].toUpperCase() + this.slice(1);
};

function transform(str) {
  return str.split(/_/)[0]+str.split(/_/).slice(1).map(s=>s.capitalize()).join("")
}

console.log(transform("snake_case"));
console
snakeCase

では,

参考

https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Regular_Expressions
https://www.freecodecamp.org/japanese/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/spinal-tap-case

GitHubで編集を提案

Discussion