正規表現で、連続した記述を簡単に書きたい
みなさん、こんにちは。
クラスでは外部から直接プロパティを参照できない様に、# 付きで隠蔽したりしますね。その場合、プロパティへの間接的なアクセスを提供するためにアクセサを設けたりする事もあるじゃないですか。
このアクセサ、(基本的なものならば)同じ記述を連続する感じになりがちで、書くのが面倒くさい と感じました。ちょうど正規表現の練習もしたかったので、この 同じ記述を連続という部分を、正規表現を使いデータを望みの形に成型 と組み合わせ、作業を簡略化させてみたいと思いました。
まあやりたいことは、正規表現の練習 ってことでお願いします。
やりたい事
- #付き隠蔽プロパティから、アクセサを作る
- データの成型は正規表現を用いる
- ゲッターとセッターは以下のような形にする
/*---仮にこのようなプロパティがあるならば… ---*/
#hoge;
/*---このようなgetter ---*/
get hoge() {
return this.#hoge;
}
/*---このようなsetter ---*/
set hoge(hoge) {
this.#hoge = hoge;
}
- プロパティ全てをコピーして関数の引数にペースト、くるくるポン
class Sample {
/*---プロパティ ---*/
#hoge;
#fuga;
hage;
#foo;
/*---プロパティここまで ---*/
constructor () {
}
}
- #付きのみなので上記では、#hoge #huga #foo のみになる
正規表現とコード作成
それでは順番にコードを作っていきます。
const makeAxesa = (props) => {
let arr = // 正規表現で値を成型し、変数arrに収めていく
}
.match()
それでは、次のコードを見て下さい。
/*---プロパティ ---*/
#hoge;
#fuga;
hage;
#foo;
/*---プロパティここまで ---*/
const makeAxesa = (props) => {
let arr = props.match(/#.+?;/g);
console.log(arr);
}
makeAxesa(`全プロパティのコピペ`);
//結果 [#hoge;, #huga;, #foo;]
先ずは上記結果の通り、#付きのプロパティのみ抽出しました。.match()は使い方に少しクセがあるので、箇条書きにしておきます。
- 文字列内に該当条件がいくつかあっても、最初の1つしかマッチしない
- 全てをマッチさせたければ、g (グローバルオプション) を付ける
- マッチした文字列は、配列 に収められコールバックされる
- テンプレートリテラル「``」で改行があると、本来の欲張りマッチが作動しない?
- 一応「?」を付けて、欲張りマッチ を回避するセーフティを掛けておく
/*---欲張りマッチとは、最長マッチ ---*/
console.log(`#hoge;#fuga;hage;#foo;`.match(/#.*;/));
//理想 ["#hoge;", "#fuga;", "#foo;"] 本当はこうなって欲しいのに…
//結果 ["#hoge;#fuga;hage;#foo;"] 最長でマッチしてしまう!
console.log(`#hoge;#fuga;hage;#foo;`.match(/#.*?;/));
//先ずは「?」を付けて最小マッチにする
//結果 ["#hoge;"] 最初の1つしかマッチしない!
console.log(`#hoge;#fuga;hage;#foo;`.match(/#.*?;/g));
//次に「g」オプションを付けて文字列全体からマッチを抽出
//結果 ["#hoge;", "#fuga;", "#foo;"] 理想の成型になった!
.replace()
それでは、次のコードを見て下さい。
const makeAxesa = (props) => {
let arr = props.match(/#.+?;/g)
.map(e => e.replace(/(#)(\w+)(;)/, '$2'));
console.log(arr);
}
makeAxesa(`全プロパティのコピペ`);
//結果 [hoge, huga, foo]
//余計な「#」と「;」を除去しました
.match()により、該当文字列が配列になって返ってきてますので、メソッドチェインで.map()を繋げ、さらにデータを成型していきます。
成型内容は、配列各要素内の文字列の頭に「#」、末尾に「;」が付いていますので、これらを取り除いていきます。
これらの除去には.replace() を使いました。$1や$2を使った、少し変わった方法を用いています。どういった方法なのかというと、
- 条件を()で囲う
- 該当した文字列が、「$1」や「$2」といった変数に収められていく
- 変数の並びを変えたり、書かないことで、文字列の入れ替えや除去が出来る
どうでしょう?自分はコレ、直感的に文字列の入れ替えや除去が出来るので、非常に気に入っている方法です。今回は、$1に「#」、$3 に「;」が入ってますので、$2のみにして、#と;の除去を行いました。
それでは、正規表現による必要なデータの成型が済みましたので、あとはこれを使って、さっくりとコードを作ります。
/*---プロパティ ---*/
#hoge;
#fuga;
hage;
#foo;
/*---プロパティここまで ---*/
/*---ゲッター & セッター作成 ---*/
const makeAxesa = (props) => {
//正規表現でプロパティの成型
let arr = props.match(/#.+?;/g)
.map(e => e.replace(/(#)(\w+)(;)/, '$2'));
//ゲッター作成
let getter = arr.map(e => `\nget ${e}() {\n return this.#${e};\n}\n`).join('');
console.log(getter);
//セッター作成
let setter = arr.map(e => `\nset ${e}(${e}) {\n this.#${e} = ${e};\n}\n`).join('');
console.log(setter);
}
/*---関数はこの形、引数はバックティック内にペースト ---*/
makeAxesa(``);
/*---全プロパティをコピペ ---*/
makeAxesa(`#hoge;
#fuga;
hage;
#foo;
`);
/*---結果 ---*/
"
get hoge() {
return this.#hoge;
}
get fuga() {
return this.#fuga;
}
get foo() {
return this.#foo;
}
"
"
set hoge(hoge) {
this.#hoge = hoge;
}
set fuga(fuga) {
this.#fuga = fuga;
}
set foo(foo) {
this.#foo = foo;
}
"
まとめ
いかがだったでしょうか?
正規表現は奥が深く、やり方も色々あるのかなと思います。
因みに自分は初級者でして、正規表現も練習中です。
もし、
- こんな方法もあるよ
- やり方違うよ
- その他
があれば、コメントでお待ちしています。