以下の内容はhttps://let.blog.jp/tag/RegExpより取得しました。


PostgreSQL の正規表現が速い
前に SQL のクエリでわざと少し遅くしようとしたことがあり 遅くなるものといえば正規表現かなと試してみましたが 想像以上に速かったです
普通の正規表現だと遅いと言ってもそんなに変わらないので 遅くなるような正規表現を探したところシンプルなのだとこういうのが見つかりました

^(\d+)*$
.+a

まずは Node.js でどれくらいかかるのか調べると

/^(\d+)*$/.test("1234567890123456789012345678a")

が 17 秒ほど
最適化されるのか 3 回目くらいから 1 秒程度になりましたけど

/.+a/.test("1".repeat(100000))

が 9.8 秒ほど
repeat で 10 万文字もありますが 「.+a」 ではなく 「a.+」 だと 1 ミリ秒未満なので 文字数が多いせいというわけではないです

これを PostgreSQL で試したのですが

postgres=# \timing
Timing is on.
postgres=# select '1234567890123456789012345678a' ~ '^(\d+)*$';
?column?
----------
f
(1 row)

Time: 2.068 ms
postgres=# select '1234567890123456789012345678a' ~ '^(\d+)*$';
?column?
----------
f
(1 row)

Time: 0.538 ms
postgres=# select '1234567890123456789012345678a' ~ '^(\d+)*$';
?column?
----------
f
(1 row)

Time: 0.675 ms
postgres=# \timing
Timing is on.
postgres=# select repeat('1', 100000) ~ '.+a';
?column?
----------
f
(1 row)

Time: 5.444 ms
postgres=# select repeat('1', 100000) ~ '.+a';
?column?
----------
f
(1 row)

Time: 5.588 ms
postgres=# select repeat('1', 100000) ~ '.+a';
?column?
----------
f
(1 row)

Time: 5.080 ms

速すぎです
数ミリ秒程度です

遅い正規表現はエンジンの実装次第なところがあるらしいですが パフォーマンスには力を入れているはずの V8 でも遅いものをこれだけの速度で実行できるというのはすごいです
ユーザ入力で遅くなりうる正規表現を実行するなら SQL として PostgreSQL 側で実行するのもありかも?
正規表現パターンマッチング
文字列のパースで 無いかもしれないものがいくつかある場合 正規表現で「?」をつけて match させてから結果を if 文で色々処理するのってわかりづらいし let 多用になるのがいまいち
「?」つけずにそれぞれのパターンで match させてパターンごとに処理をさせたほうがわかりやすいかも

こういう関数を用意して

const match = (str, patterns) => {
for(const [cond, fn] of patterns) {
if (cond == null) return fn()
const matched = cond instanceof RegExp ? cond.exec(str) : str.match(cond)
if (matched) return fn(matched, ...matched)
}
}

こう使う

const tes = str => {
const result = match(str, [
[/^(\d+)$/, (_, __, d) => [+d, +d]],
[/^(\d+),$/, (_, __, d) => [+d, null]],
[/^,(\d+)$/, (_, __, d) => [null, +d]],
[/^(\d+),(\d+)$/, (_, __, d1, d2) => [+d1, +d2]],
[null, () => [null, null]],
])
console.log(result)
}

tes("10,20") // [10, 20]
tes("30,") // [30, null]
tes(",40") // [null, 40]
tes("50") // [50, 50]
tes("") // [null, null]

見やすさはイマイチかも
match と replace の検索するテキストに文字列型渡したときの違い
忘れた頃に引っかかるやつ

console.log("1.2".replace("1.2", "X")) // X
console.log("102".replace("1.2", "X")) // 102

console.log("1.2".replaceAll("1.2", "X")) // X
console.log("102".replaceAll("1.2", "X")) // 102

console.log("1.2".match("1.2")) // ["1.2", index: 0, input: "1.2", groups: undefined]
console.log("102".match("1.2")) // ["102", index: 0, input: "102", groups: undefined]

console.log("1.2".matchAll("1.2").next().value) // ["1.2", index: 0, input: "1.2", groups: undefined]
console.log("102".matchAll("1.2").next().value) // ["102", index: 0, input: "102", groups: undefined]

match は文字列型でも正規表現としてマッチングされる
replace の挙動に揃えてほしいけど互換性重視で実現されないだろうね

ただの match だと正規表現にしたくないなら indexOf や includes で良かったけど matchAll は indexOf 繰り返すの面倒だから文字列型として使いたいのに
Firefox の正規表現エンジンが V8 と同じものになるみたい
https://www.publickey1.jp/blog/20/mozillav8firefox.html

Firefox は最新機能を積極的に取り入れてるものの正規表現だけは対応してませんでした
http://var.blog.jp/archives/81194754.html

これまでも V8 と同じエンジンではあったものの Firefox 用にフォークしていて 新機能があるたびその変更を取り込んでいたようです
この作業に時間がかかっていたようで Firefox 用にフォークするのではなく V8 と同じものをそのまま使えるようにするのだとか

これで Firefox でも正規表現の最近の新機能が使えるようになりそうです
未対応だった正規表現機能も今月末にリリース予定の 78 から使えるらしいので 78 からこの新しい仕組みになってるのかもしれませんね
正規表現の Unicode Property
new RegExp(/\p{sc=Hiragana}/u)

みたいなの
他言語だと 「sc=」 がいらないようでそれを参考にしたらエラーが出る

JavaScript の Unicode Property の指定方法はこれ

// Non-binary values
\p{UnicodePropertyValue}
\p{UnicodePropertyName=UnicodePropertyValue}

// Binary and non-binary values
\p{UnicodeBinaryPropertyName}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes

「For most values, the UnicodePropertyName part and equals sign may be omitted.」(ほとんどの値で UnicodePropertyName とイコール記号は省略できる)って書いてるのに Hiragana はだめらしい

その他指定できるプロパティの一覧
https://www.ecma-international.org/ecma-262/10.0/index.html#sec-runtime-semantics-unicodematchproperty-p

ECMAScript のスペックは whatwg みたいに分割版がなくて ES2019 が全部入りのページなせいでかなり重い
今後更新されないはずだけどそう変わるものでもないので 提案時のスペック見るのもあり

https://tc39.es/proposal-regexp-unicode-property-escapes/#sec-runtime-semantics-unicodematchproperty-p
正規表現の */ が地味に迷惑
function a(str) {
const reg = /\d*/g
return reg.test(str)
}

こんな感じのコードがあってまとめてコメントアウトしたいから /**/ で囲んだのになんかエラーでてる
確認してみたら 正規表現の */ でコメントが終わってて それ以降が JavaScript として扱われて構文エラー

正規表現リテラルが 「/」 なの地味に困る

ブロックコメントのネスト機能もないし その行の最初に // 入れてもコメント中なら無意味だし */ の後に入れたらコードの途中だからコメントアウトを外すとき辛いし
ブロックコメントは使わず矩形選択してブロックコメント化したいところ全行の最初に // 入れるのが良いのかな
正規表現で m をつけても行をまたいでマッチする
行頭の - を消したいとき
`
- a-1
- b-2
- c-3
`.replace(/^\- /g, "")
// "
// - a-1
// - b-2
// - c-3
// "
だと ^ が1行目にしかマッチしないので消えてくれない

m オプションをつけるとそれぞれの行にマッチするので消せる
`
- a-1
- b-2
- c-3
`.replace(/^\- /gm, "")
// "
// a-1
// b-2
// c-3
// "

この方法でインデントを消そうとしたら
`
a
b
c
d
`.replace(/^\s{4}/gm, "")
// " a
// b
// c
// d
// "
なぜか a だけ前に空白が残ってる

原因は実行時には 1 行目のマッチで \n と次の行の半角スペース 3 つまでマッチしてるから
空白文字 4 つは \n を含んでそのまま次の行も対象になってる

a のある行の ^ はすでにマッチしてる部分になるので この行の空白はマッチしない
a の前にスペースが 10 個あっても 3 つ削られた 7 つが残る

改行文字がマッチしないように \s より半角スペースは \t をちゃんと指定したほうが良さそう



以上の内容はhttps://let.blog.jp/tag/RegExpより取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14