0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

バックヤード 正規表現

Posted at

こんばんは。初投稿です。正規表現についてまとめました。

使い方

「なんで使い方からやねん!」ってツッコミたくなりますよね。
正規表現は文字を探すためにあります。

/a/.test('I am neko.');// -> true

/a/.test('文字')aを文字の中から見つけるという意味で、今回はamのaにヒットします。
ほかにも

/a/.exec('I am neko.');
/* ->
Object.assign(['a'], {
    index: 2,
    input: 'I am neko.',
    groups: undefined
})
*/

indexを使って場所を調べたりできます。

作り方

/パターン/フラグ
new RegExp('パターン', 'フラグ')

パターンとフラグはあとでね。

/t/i.exec('This is test.');
new RegExp('t', 'i').exec('This is test.');
// 2つとも同じ
/* ->
Object.assign(['T'], {
    index: 0,
    input: 'This is test.',
    groups: undefined
})
*/

パターン

パターンの書き方を教えます。覚えたらすごいね。

文字

ふつうの文字です。同じ文字があったらマッチします。

/a/.test('tasty');// a
/bc/.test('abcde');// bc

「もしくは~」です。[abc][a-c]a|b|cは全て同じです。

/[abc]/.test('symbol');// b
/[abc][abc]/.test('ban');// ba
/[a-e]/.test('suck');// c
// [a-e]は[abcde]と同じ意味
/ab|cd/.test('acd');// cd
/[0-9a-z]/.test('JACKP0T');// 0
/[9-0]/.test('JACKP0T');// エラー
// [z-a]、[9-0]などは順番が違う

「ではない~」です。[^]と書きます。

/[^a-zA-Z]/.test('Testing:complete');// :
/[^abc]/.test('back');// k

「なにか」です。なにかがある。.と書きます。

/b.d/.test('abcde');// bcd
/b..d/.test('abandon');// band

文字セットです。大文字になると反転します。

/\d/.test('I am number 011.');// 0
// [0-9]と同じ
/\D/.test('011: me');// :
// [^\d]と同じ

/\w/.test('アイスクリームyou scream');// y
// [a-zA-z0-9_]と同じ。アンダーバーも忘れずに。
/\W/.test('I screamユースクリーム');//  
// ユじゃないよ~

/\s/.test('ねこちゃん わんちゃん');//
// スペースと区切り文字(全角、半角、タブ、改行など)に反応します。
/\S/.test('  \n\f\v\r\t  
ここまで来たら真の\\S');// こ
// これからはスペースを打つ代わりに\sを使います。

繰り返し

めっちゃ簡単です。よかったね。
n回繰り返す」です。文字{n}と書きます。
文字をまとめるときは(?:)と書きます。

/(?:にゃん){2}/.test('にゃんにゃん');// にゃんにゃん
/わん{3}/.test('わんんん');// わんんん

n回以上繰り返す」は文字{n,}と書きます。

/(?:のこ){1,}/.test('のこのこ');// のこのこ
// 「のこ」じゃないです
/(?:のこ){0,}/.test('none');//
// ''が結果です

nからm回繰り返す」のは文字{n,m}と書きます。

/(?:らく){1,3}/.test('らくらく');// らくらく
// 「らく」じゃないです
/(?:らく){0,1}/.test('らくらく');// らく

特別な繰り返し記号があります。

省略 繰り返し
文字* 文字{0,}
文字+ 文字{1,}
文字? 文字{0,1}
/ねこ*/.test('ねっこ');// 
/ねこ+/.test('ねこ');// ねこ
/ねこ(?:ちゃん)?/.test('ねこ');// ねこ

位置(アサーション)

文字の位置を決めるためのものです。結果にはふくまれません。ここが少し難しいです。
最初の文字と最後の文字です。^$と書きます。

/^[abc][def][ghi]$/.test('beg');// beg

文字じゃないもの(A-Za-z0-9_)です。\bと書きます。文字は\Bです。

/\bword/.test('a word');// word
// \bは文字じゃないのでスペースは含まない
/\Bward/.test('forward');// ward
// forのrは含まない

前置、後置です。(?<=)(?=)

/(?<=thank\s)you/.test('thank you');// you
/thank(?=\syou)/.test('thank you');// thank

ではないバージョンです。(?<!)(?!)

/(?<!thank\s)you/.test('here you are');// you
/thank(?!\syou)/.test('thanks');// thank
アサーションについて

解説パートをたまに挟んでみる。
アサーションで注意するべきなのは、それ自体は結果に含まれないということです。
では突然の問題

/a(?<=\s)b/.test('文字');// -> true

これが成立する文字はなんでしょうか?
正解はありません。なぜ無いのかというと、(?<=\s)が文字じゃないからです。ステップを踏んで考えてみましょう。
ステップ1: /(?<=\s)b/\sが前にあるbにマッチします。
つまり、/a(?<=\s)b/\sbの前にあるabにマッチします。\sbabを同時に満たさなければならないのでありえません。
ちなみにアサーションは一番前と後ろに書く以外意味が無いです。

フラグ

どんな風に文字を探すか決めます。

i

iフラグは大文字と小文字を無視して探すことができます。

/thank\syou/i.test('Thank you');// Thank you
/U\sR/i.test('U r url');// U r

g

gフラグは挙動をガラリと変えます。だいたい「全てを探す」と思ってください。gフラグがないとエラーを出す関数も在ったりします。

let a = /a/,
    b = /a/g;

a.test('apple');// -> true
console.log(a.lastIndex);// > 0
console.log(a.test('apple'));// > true

b.test('apple');// -> true
console.log(b.lastIndex);// > 1
b.test('apple');// > false

lastIndexが使えるようになったり、lastIndexから調べ始めたりします。
関数ごとに挙動がかなり変わるのであとでやります。

d

indicesというプロパティを生成します。

let result = /dea/d.exec('idea');
console.log(result.indices);
/* >
Object.assign([[1, 4]], {
    groups: undefined
});
*/

m

^$が文字列のはじめと終わりに加えて、行のはじめにもマッチするようになります。

/^I/m.test(`hi.
I ate it.`);// I

s

.が改行にもマッチするようになります。

/an.apple/s.test(`an
apple`);// 'an\napple'

使い方

「いや二回目やん!」ってツッコミたくなりますよね。これでこの記事は終わりです!最後まで頑張っていきましょう!
前に紹介したtestexec以外まだ関数はあるので見ていきましょう。

//.test()

マッチするものがあればtrueなければfalseを返します。
gフラグなし

const regex = /[^\w\s]/;
regex.test('Yes, I did.');// ,
regex.test('Yes, I did.');// ,

gフラグあり

const regex = /[^\w\s]/g;
regex.test('Yes, I did.');// ,
regex.test('Yes, I did.');// .
regex.test('Yes, I did.');// -> false

//.exec()

マッチしたときは配列、しないときはnullを返します。
gフラグなし

const regex = /\w+/;
regex.exec('an apple as an accessory');
/* ->
Object.assign(['an'], {
    index: 0,
    input: 'an apple as an accessory',
    groups: undefined
});
*/
regex.exec('an apple as an accessory');// 同じ

gフラグあり

const regex = /\w+/g;
regex.exec('an apple as an accessory');// -> ['an']
regex.exec('an apple as an accessory');// -> ['apple']

''.match()

gフラグなし
gフラグなしの時のexecと同じです。

const regex = /a/;
'apple'.match(regex);// -> regex.exec('apple')

gフラグあり
マッチした文字を配列で返します。

const regex = /a[a-z]*/g;
'apple banana'.match(regex);// -> [apple, anana]
'none'.match(regex);// -> null

''.matchAll()

gフラグなし
エラーです。_| ̄|○ ガックシщ(´□`)щ オーマイガーッ!!
gフラグあり
execの結果がつまったイテレーターを返します。

イテレーターの使い方

たまに聞くけどあんま分からないんだなーとか聞いたこともないんだなーっていう人のための使い方二選!

[...イテレーター];// -> [値1, 値2, …]
for (const 変数 of イテレーター) {
    console.log(変数);
}
/* >
* 値1
* 値2
* ...
*/

ちなみに一度使ったイテレーターはもうゴミです。

const result = 'big bamboo'.matchAll(/b/g);
for (const val of result) {
    console.log(val);
}
/***** 下のコードと同じ *****/
const regex = /b/g;
while (true) {
    const result = regex.exec('big bamboo');
    if (result === null) {
        break;
    } else {
        console.log(result);
    }
}
console.log([...'big bamboo'.matchAll(/b/g)]);

''.replace()

指向が変わって今度は文字を置き換えます。ここが山場です。ここを超えたらあとはウイニングランを楽しんでください。
gフラグなし
一番最初にマッチしたものを置き換えます。

'3匹の猫、2匹の犬'.replace(/\d/, '');// -> 何匹の猫、2匹の犬

gフラグあり
すべて変換します。

'3匹の猫、2匹の犬'.replace(/\d/g, '');// -> 何匹の猫、何匹の犬

共通
ここで終わりだと思ったら大間違いです。

記号 意味
$$ 「$」(エスケープ)
$& マッチした文字
$` マッチした文字の前
$' マッチした文字の後
'cocoa'.replace(/o/g, "$`");// -> 'ccccoca'
// c c(o) c coc(o) a
'cocoa'.replace(/o/g, "$'");// -> 'ccoacaa'
// c coa(o) c a(o) a

'11匹の猫'.replace(/\d+/g, "$&0");// -> '110匹の猫'

'10ドル'.replace(/ドル|dollar/g, "$$");// -> '10$'

まだ終わらないよ( `ー´)ノ
関数を入れるとまた違った動きをします。

String.prototype.replace()
'str'.replace(正規表現, (マッチした文字, インデックス, 文字全部) => 置き換える文字)
'97点'.replace(/\d/g, match => {
    const kanjiNum = ['', '', '', '', '', '', '', '', '', ''];
    return kanjiNum[match];
});// -> '九七点'
'あああ0いいい0ううう'.replaceAll(/0/g, (match, index, str) => {
    console.log(match, index, str);
});
/* 出力結果:
* '0', 3, 'あああ0いいい0ううう'
* '0', 7, 'あああ0いいい0ううう'
*/

おしまい!ウイニングラン楽しんでね★

''.replaceAll()

gフラグなし
エラーです。Allが付いてるのにgフラグ忘れるとかなめてんのか(; ・`д・´)
gフラグあり
gフラグありのときのreplace()と同じです。

replace()との違い

正規表現を使う場合、違いはありません。文字を引数にするときに違いがでます。

'an apple'.replace('a', 'A');// -> 'An apple'
'an apple'.replaceAll('a', 'A');// -> 'An Apple'

''.search()

マッチした文字の最初のインデックス(場所)を返します。

const regexWg = /apple/g;
'I like apples'.search(regex);// -> 7
'I like apples'.search(regex);// -> 7

const regexWOg = /apple/;
'I like apples'.search(regex);// -> 7
'I like apples'.search(regex);// -> 7

gフラグありとなしで同じ結果を出します。gフラグは影響しません

''.split()

区切って配列を作ります。

const regexWg = /,/g;
'月,火,水,木,金,土,日'.split(regexWg);// -> ['月', '火', '水', '木', '金', '土', '日']
'月,火,水,木,金,土,日'.split(regexWg);// -> ['月', '火', '水', '木', '金', '土', '日']

const regexWOg = /,/;
'月,火,水,木,金,土,日'.split(regexWOg);// -> ['月', '火', '水', '木', '金', '土', '日']
'月,火,水,木,金,土,日'.split(regexWOg);// -> ['月', '火', '水', '木', '金', '土', '日']

gフラグありとなしで同じ結果を出します。gフラグは影響しません

その他

ここまで学んだらだいたいなんでもできます。おめでとうございます!でもまだあります\(^o^)/オワタ
余力があったら読んでね。

lastIndex

正規表現オブジェクトにはlastIndexというプロパティが存在します。その値によって返す値が変わります。

test()

gフラグなし
影響しません。影響されません。
gフラグあり
lastIndexから検索し始めます。
lastIndexがヒットした文字の場所+1になります。

const regex = /an?/g;
console.log(regex.lastIndex);// > 0
// デフォルトは0
regex.test('an apple');
console.log(regex.lastIndex);// > 2
// anの最後の文字(n)のインデックス(0)プラス1(2)
regex.test('an apple');
console.log(regex.lastIndex);// > 4
// aのインデックス(3)プラス1(4)
regex.test('an apple');// -> false
console.log(regex.lastIndex);// > 0
// 一周すると0に戻る

regex.lastIndex = 2;
regex.test('a dog');// -> false
// dから探し始める

exec()

gフラグなし
影響しません。影響されません。
gフラグあり
仕組みはtest()と同じです。

const regex = /an/g;
regex.exec('an apple and a banana');
console.log(regex.lastIndex);// > 2
regex.exec('an apple and a banana');
console.log(regex.lastIndex);// > 11
regex.exec('an apple and a banana');
console.log(regex.lastIndex);// > 18

regex.lastIndex = 1;
regex.exec('an apple and a banana');
console.log(regex.lastIndex);// > 11

matchAll()

影響しませんが影響されます。

const regex = /an/g;
regex.lastIndex = 4;
console.log([...'an apple and a banana'.matchAll(regex)]);
// (an)dとb(an)(an)aの3つ

最初は本当にバグだと思った。

貪欲モード

/(?:のこ)+/.test('のこのこ');// のこのこ
// 「のこ」じゃないです

これを「のこ」にする方法が存在するんです。
後ろに?をつけると最低限でとめることができます。

/ねこ(?:にゃん)?/.test('ねこにゃんにゃん');// ねこにゃん
/ねこ(?:にゃん)*/.test('ねこにゃんにゃん');// ねこにゃんにゃん
/ねこ(?:にゃん){1,}/.test('ねこにゃんにゃん');// ねこにゃんにゃん
/ねこ(?:にゃん)??/.test('ねこにゃんにゃん');// ねこ
/ねこ(?:にゃん)*?/.test('ねこにゃんにゃん');// ねこ
/ねこ(?:にゃん){1,}?/.test('ねこにゃんにゃん');// ねこにゃん

バックリファレンス

量は多いですが質はそこそこです。さくさく行きましょ。
あとから使うためにグループで囲っておきます。

記号 説明
() 括弧内の文字列を、後で参照するために使用されます。
(?<group>) 一致した文字列に名前(グループ)を付ます。
\1, \2... n番目の文字列を参照します。(例:\1 は最初の括弧内の文字列を参照)
\k<group> (?<group>) で作成されたグループの文字列を参照します。
/([a-z])\1/.test('foo');// oo
// [a-z][a-z]とは違い「fo」にマッチしない
// 同じ小文字アルファベットが2つ並ぶとマッチ
/(?<letter>[a-z])\k<letter>/.test('foo');// oo
// 同じ原理
/(?<letter>[a-z])\1/.test('foo');// oo
// 名前付きキャプチャグループもグループとして数えられる
/(ab){2}(?<name>cd){2}/.test('ababcdcd');// ababcdcd
// (?:)と同じように使える

ここからマッチした後の話をしていきますね。
関数の振る舞いも変わってきます。

exec()

const result = /(a|an|the)\s(?<word>\w+)/.exec('there are an apple and a cat');
console.log(result[0]);// > an apple
console.log(result[1]);// > an
// 1つ目のグループの文字列
console.log(result[2]);// > apple
// 2つ目のグループの文字列
console.log(result.groups);// > { word: 'apple' }
// 「グループ名:文字列」のように保管されます

indicesプロパティも変わります。

const result = /(a|an|the)\s(?<word>\w+)/d.exec('there are an apple and a cat');
console.log(result.indices[0]);// > [10, 18]
console.log(result.indices[1]);// > [10, 12]
// 1つ目のグループのインデックス
console.log(result.indices[2]);// > [13, 18]
// 2つ目のグループのインデックス
console.log(result.indices.groups);// > { word: [13, 18] }
// 「グループ名:インデックス」のように保管されます

手抜きじゃないです(;'∀')

replace()

$n$<group>が追加されます。

'an apple'.replace(/(a|an|the)\s(?<word>\w+)/g, '$1(冠詞) $<word>(名詞)');
// -> an(冠詞) apple(名詞)

関数にも新しく引数が追加されます。

'str'.replace()
''.replace(regex, (マッチした文字, 括弧1, 括弧2, ..., インデックス, 元の文字列, グループ) => 文字列);
'an apple'.replace(/(a|an|the)\s(?<word>\w+)/g, (match, n1, n2, index, string, group) => {
    // ずれるため、n2は省略できない
    let result = '';
    if (n1 === 'the') {
        result += 'その';
    } else {
        result += '一つの';
    }
    result += group.word;
    console.log(match, n1, n2, index, string, group);
    return result;
});// -> 一つのapple
/*
* match: an apple マッチした文字列
* n1: an グループ1
* n2: apple グループ2
* index: 0 インデックス
* string: an apple 全体の文字
* group: { word: 'apple' } グループ
*/

split()

グループされたら結果に含まれるようになります。

'{name}apple{price}500{description}sweet'.split(/{(.*?)}/);// あり
// -> ['', 'name', 'apple', 'price', '500', 'description', 'sweet']

'{name}apple{price}500{description}sweet'.split(/{.*?}/);// なし
// -> ['', 'apple', '500', 'sweet']

エスケープとuvフラグ

正真正銘の最後です。おおとりにして山場です。
これらは普通の文字列の時と同じです。

\f, \n, \r, \t, \v
\\
\0
\xhh, \uhhhh
同じだからって説明しなくて良い訳じゃ無いからね?
エスケープ 意味 説明
\f フォームフィード 用紙を次のページへ進める。(現在はほとんど使用されない)
\n 改行 カーソルを次の行の先頭へ移動。(改行)
\r キャリッジリターン カーソルを現在の行の先頭へ移動。(\nと組み合わせて使用される)
\t 水平タブ タブスペースです。
\v 垂直タブ カーソルを次の垂直タブ位置へ移動。(現在はほとんど使用されない)
\\ バックスラッシュ バックスラッシュです。
\0 ヌル文字 ヌル文字(U+0000)です。(次の文字が数字の場合オクタルエスケープ(非推奨)になります)
\xhh 16進数エスケープ 2桁の16進数値(hh)に基づいて文字を表します。(U+0000~U+00FF)
\uhhhh Unicodeエスケープ 4桁のUnicodeコードポイント(hhhh)を使用して文字を表します。(U+0000~U+FFFF)

ここから正規表現のみのエスケープです。

[\b]
// バックスペース文字です。文字列での\bと同じです。
// \bだけだとアサーションになります。
\ca, \cb, \cc, ... \cz
// aはU+0001, bはU+0002, ...
// 大文字でも同じです。

パターンで使われる文字はいろいろエスケープできます。

\{, \), \$, \?, ...
一覧

おさらいと共に、エスケープが必要な記号すべてを載せておきます。

記号 おさらい
() (abc) 後で使う用にデータをとっておく
[] [a-z] a~zのどれかがあればマッチ
{} a{2,4} aa~aaaaにマッチ
. a.b acbやalbにマッチ
/ /abc/ abcにマッチ
* ba* b, ba, baa, ...にマッチ
+ ba+ ba, baa, baaa, ...にマッチ
? ba? bかbaにマッチ
$ abc$ 文の最後のabcにマッチ
^ ^abc 文の最初のabcにマッチ
| abc|cba abcかcbaにマッチ
- [a-z] []の中だけで有効

ウォーミングアップは終わり。

uフラグ

新しいフラグです。

サロゲートペア

では問題です!

// あてはまる文字はなんだ?
/😀{2}/.test(文字);// -> true
// 制限時間: 10秒

正解は~?😀\ude00でした~
サロゲートペアといって文字が二つに分割されてるんです。\u0000~\uffffまでの65536文字だとすべて表せなかったんですね~

console.log(😀[0]);// > '\uD83D'
console.log(😀[1]);// > '\uDE00'
// U+D83D・\uDE00自体は文字が設定されていないため�が表示されます
サロゲートペアの計算方法

unicode上のU+10000以上U+10FFFF以下の文字をUTF-16であらわす(計算)方法を載せておきます。
😀で実践してみます。😀はU+1f600です。

// 😀のコードポイント
const code = 0x1F600;

// codeと0x10000からの差分をとる
const offset = code - 0x10000;
console.log(offset.toString(2).padStart(20, '0'));
// > 00001111011000000000

// 上位・下位10ビットをとる
const high10Bits = offset >> 10;
console.log(high10Bits.toString(2).padStart(10, '0'));
// > 0000111101

const low10Bits = offset & 0b1111111111;
console.log(low10Bits.toString(2).padStart(10, '0'));
// > 1000000000

// 上位・下位サロゲートを足す
const highSurrogate = 0xD800 + high10Bits;
console.log(highSurrogate.toString(16));
// > d83d

const lowSurrogate = 0xDC00 + low10Bits;
console.log(lowSurrogate.toString(16));
// > de00

console.log('\ud83d\ude00');// > 😀

上位・下位サロゲートとは上位・下位サロゲート領域(サロゲート文字処理のために文字が割り当てられていないコードポイント範囲)に合わせるために足されるものです。
上位サロゲートはU+D800U+DBFFで下位サロゲートはU+DC00U+DFFFまでです。
どちらも範囲は1024です。(0~1111111111)
これで1048576(2^20)文字使えるようになりました。

しかしこれをuフラグを使うことで回避できます。

/😀{2}/u.test('😀😀');// -> true

さらにuフラグを使うとunicodeエスケープを使うことができます。

/\u{1f600}/u.test('😀')// -> true
p{}、P{}

uフラグを使っているときはp{}P{}が使えるようになります。P{}[^p{}](p{}の逆)です。
p{General Category}
UnicodeプロパティのGeneral categoryを使って文字を指定することができます。

let regex;
regex = /\p{Lu}/u;
regex.test("A");// -> true
regex.test('Γ');// -> true
regex.test('a');// -> false
// Luは大文字にマッチ

regex = /\p{Ll}/u;
regex.test('a');// -> true
regex.test('γ');// -> true
regex.test('A');// -> false
// Llは小文字にマッチ

regex = /\p{Nd}/u;
regex.test("");// -> true
regex.test("2");// -> true
// Ndは数字にマッチ

regex = /\p{P}/u;
regex.test(".");// -> true
regex.test(",");// -> true
// Pは記号にマッチ

regex = /\P{P}/u;
regex.test(".");// -> false
regex.test(",");// -> false
// 大文字は反転する
全種類

AIに作成させました。大体信用できるかな。

名前 説明
L Letter アルファベット文字 A,b,α,漢 約136,000
LC Cased Letter 大文字、小文字、タイトルケースの文字 A,a,Dž 約4,100
Lu Uppercase Letter 大文字のアルファベット A,B,C 約1,800
Ll Lowercase Letter 小文字のアルファベット a,b,c 約2,200
Lt Titlecase Letter タイトル用の特殊な文字 Dž(例:"Džuro") 約30
Lm Modifier Letter 他の文字を修飾する文字 ˇ,ˋ 約300
Lo Other Letter 他のサブカテゴリに属さない文字 漢,अ 約130,000
M Mark ベース文字と組み合わせる記号 ◌́,◌⃝ 約2,000
Mn Non-Spacing Mark ベース文字に付属し、間隔を追加しないマーク ◌́(アクセント) 約1,700
Mc Spacing Combining Mark 結合後に間隔を追加するマーク ◌ा(デーヴァナーガリー) 約300
Me Enclosing Mark 他の文字を囲む記号 ◌⃝(円形マーク) 約20
N Number 数字 1,Ⅻ,⅔ 約1,000
Nd Decimal Digit 通常の数字 0–9 約650
Nl Letter Number 文字の形をした数字 Ⅻ,Ⅶ 約170
No Other Number 分数や特殊な数字 ⅔,㊾ 約180
P Punctuation 文や文章を整理する記号 .,?,“,” 約1,000
Pc Connector Punctuation テキストセグメントを接続する記号 _ 約10
Pd Dash Punctuation ダッシュ -,- 約20
Ps Open Punctuation 開く括弧や引用符 {,(,“ 約50
Pe Close Punctuation 閉じる括弧や引用符 },),” 約50
Pi Initial Quote 開始用の引用符 約10
Pf Final Quote 終了用の引用符 約10
Po Other Punctuation その他の句読点 !,&,/ 約850
S Symbol さまざまな記号 $,♠,☀ 約8,000
Sm Math Symbol 数学的操作の記号 +,÷,∑ 約1,000
Sc Currency Symbol 通貨を表す記号 $,¥,€ 約70
Sk Modifier Symbol 他の記号の意味を修飾する記号 ^,~ 約120
So Other Symbol その他の特殊な記号 ♠,☀,☎ 約6,800
Z Separator 空白や改行を表す文字 スペース,改行 約20
Zs Space Separator 通常の空白 スペース,NBSP 約17
Zl Line Separator テキスト行を分割する 行セパレーター 1
Zp Paragraph Separator テキスト段落を分割する 段落セパレーター 1
C Other 見えない文字やその他の文字 Null,ZWNJ 約65
Cc Control 制御用の文字 NULL,ESC 約65
Cf Format 書式コード ZWNJ,ZWJ 約160
Cs Surrogate サロゲートペアを構成する高位または低位の符号 High Surrogate 2048
Co Private Use カスタム用途の文字 カスタムコードポイント 約137,000
Cn Not Assigned 使用されていないコードポイント 予約済みポイント 可変 (残りの範囲)

To get further information, please visit the link below.
https://en.wikipedia.org/wiki/Template:General_Category_(Unicode) (英語です)

\p{sc=}
\p{sc=言語}\p{scx=言語}でその言語の文字を指定できます。

/\p{sc=Latin}/u.test('abc');// -> true
/\p{sc=Cyrillic}/u.test('л');// -> true
/\p{sc=Greek}/u.test('λ');// -> true
/\p{sc=Arabic}/u.test('ف');// -> true
/\p{sc=Devanagari}/u.test('ख');// -> true

/\p{sc=Katakana}/u.test('ニ');// -> true
/\p{sc=Hiragana}/u.test('ゃ');// -> true
/\p{sc=Han}/u.test('一');// -> true
// Hanは漢字や中国語にマッチ

/\p{sc=Hira}/u.test('。');// -> false
/\p{scx=Hira}/u.test('。');// -> true
// scxを使うとその言語っぽい物にもマッチ

/\p{Script=Hiragana}/u.test('。');// -> false
/\p{Script_Extensions=Hiragana}/u.test('。');// -> true
// scとscxは実はこれらの略
他の例

全種類じゃないです。もちろん追加されたりもします。AI生成です。

説明 例の文字
Latin 多くのヨーロッパ言語および他の多くの言語で使用されます。 A,B,C,a,b,c
Cyrillic スラブ語および一部の非スラブ語で使用されます。 Б,Д,Ж
Arabic アラビア語および一部の他の言語(例:ウルドゥー語)で使用されます。 ا,ب,ت
Devanagari ヒンディー語、サンスクリット語、および他のインド言語で使用されます。 अ,आ,इ
Han 中国語、日本語、韓国語の文字システムで使用されます。 日,本,語
Greek ギリシャ語および数学記号で使用されます。 Α,Β,Ω
Hebrew ヘブライ語および礼拝の文書で使用されます。 א,ב,ג
Thai タイ語および関連する文字システムで使用されます。 ก,ข,ค
Armenian アルメニア語で使用されます。 Ա,Բ,Գ
Bengali ベンガル語、アッサム語、および関連する言語で使用されます。 অ,আ,ই
Tibetan チベット語、ゾンカ語、および他のヒマラヤ言語で使用されます。 ཀ,ཁ,ག
Georgian ジョージア語で使用されます。 ა,ბ,გ
Malayalam インドのケーララ州で使われるマラヤーラム語で使用されます。 അ,ആ,ഇ
Sinhala スリランカのシンハラ語で使用されます。 අ,ආ,ඉ
Cherokee ネイティブアメリカン起源のチェロキー語で使用されます。 Ꭰ,Ꭱ,Ꭲ
Kannada インドのカルナータカ州で使われるカンナダ語で使用されます。 ಅ,ಆ,ಇ
Runic 古代のゲルマン語で使用された歴史的な文字システムです。 ᚠ,ᚢ,ᚦ
Katakana 日本語の音節文字で、主に外来語に使用されます。 カ,キ,ク
Glagolitic 中世のスラブ語で使用された歴史的な文字システムです。 Ⰰ,Ⰱ,Ⰲ
Thaana モルディブのディベヒ語で使用されます。 ހ,ށ,ނ
Gujarati インドのグジャラート語で使用されます。 અ,આ,ઇ
Gurmukhi 主にインドで使用されるパンジャブ語で使用されます。 ਅ,ਆ,ਇ
Oriya インドのオリヤ語で使用されます。 ଅ,ଆ,ଇ
Limbu ネパールやインドで使用されるリンブ語で使用されます。 ᤀ,ᤁ,ᤂ
Mongolian 縦書きで書かれるモンゴル語で使用されます。 ᠠ,ᠡ,ᠢ
Syriac 古典的および現代のシリア語、また礼拝用に使用されます。 ܐ,ܒ,ܓ
Myanmar ミャンマーのビルマ語と関連言語で使用されます。 က,ခ,ဂ
Phags_pa 元朝時代に多言語で使用された歴史的な文字システムです。 ꡀ,ꡁ,ꡂ
NKo 西アフリカのンコ語で使用されます。 ߊ,ߋ,ߌ
Ol_Chiki インドのサンタリ語で使用されます。 ᱚ,ᱛ,ᱜ

下のリンクはすべての有効な値のリストです。
https://tc39.es/proposal-regexp-unicode-property-escapes/#table-unicode-script-values

\p{バイナリプロパティ}
\p{バイナリプロパティ}と書くとバイナリプロパティがtrueな文字にマッチします。

let regex;

regex = /\p{Alphabetic}/u;
regex.test('a');// -> true
regex.test('');// -> true
// アルファベットにマッチ

regex = /\p{White_Space}/u;
regex.test(' ');// -> true
regex.test('\t');// -> true
// 空白にマッチ

regex = /\p{Lowercase}/u;
regex.test('a');// -> true
regex.test('γ');// -> true

/\p{Emoji}/u.test('🤪');

regex = /\p{Math}/u;
regex.test('Σ');// -> false
regex.test('×');// -> true
// 算数の記号にマッチするはず
その他

AI生成です。こんなにAIを使った記事は過去にないんじゃないかな。

プロパティ名 説明
Alphabetic アルファベットの一部である文字に対してtrueになります。 A,Б,あ
White_Space 空白とみなされる文字に対してtrueになります。 スペース,タブ,改行
Uppercase 大文字のアルファベット文字に対してtrueになります。 A,Б,Α
Lowercase 小文字のアルファベット文字に対してtrueになります。 a,б,α
Numeric 数字や数値の文字に対してtrueになります。 0-9,๙
ID_Start プログラミング言語で識別子を開始できる文字に対してtrueになります。 A,_,α
ID_Continue 識別子の最初の文字以降に続けられる文字に対してtrueになります。 0,1,_
Emoji 絵文字として定義されている文字に対してtrueになります。 😊,🍎,🚗
Math 数学記号として使用される文字に対してtrueになります。 +,×,∫
Diacritic 基本文字の音を変更する文字に対してtrueになります。 ´,^
Case_Ignorable 大文字小文字を区別する比較で無視される文字に対してtrueになります。 ',˘
Default_Ignorable_Code_Point 表示に無視されるべき文字に対してtrueになります。 U+200D
Grapheme_Base 単独のグラフェムとして機能する文字に対してtrueになります。 A,क,あ
Grapheme_Extend グラフェムを拡張する文字に対してtrueになります。 ´,़
Quotation_Mark 引用符として使用される文字に対してtrueになります。 ",‘,»
Dash ダッシュとして機能する文字に対してtrueになります。 -,–,—
Hex_Digit 16進数で有効な文字に対してtrueになります。 0-9,A-F,a-f
Logical_Order_Exception テキストの論理順序に例外となる文字に対してtrueになります。 一部のインド母音
Soft_Dotted 軟点を持つ文字に対してtrueになります。 i,j
Variation_Selector 他の文字の表示に変化を示す文字に対してtrueになります。 U+FE0F

全プロパティのリストです。scと違ってみただけじゃなんだか分からないけどね。
https://tc39.es/proposal-regexp-unicode-property-escapes/#table-binary-unicode-properties

vフラグ

本当の最後です。今までのが嘘とは言わない。vフラグはuフラグの拡張で、uフラグで使える機能に加える形になります。

書記素クラスタ

まず「グ」という文字は信じられないと思いますが一文字です。もちろん大半の人はU+FF77(ク)U+FF9E(゙)の二文字だと勘違いしていたと思いますが。
書記素クラスタはこのように2文字(以上)を1文字にまとめて文字の境界を決めるシステムです。カーソルを動かしたり、文字を数えたりするときに良かったりします。
vフラグはそういう文字を判定するときに使います。

\p{binaryUnicodePropertyOfStrings}

いままではコードごとに与えられたプロパティを使えばよかったのですが(例えば文字「a」のScript(sc)プロパティの値はLatinです)、2文字ひとセットとなるとまた違った対応が必要です。
なのでそういう文字をリスト化して正規表現で使えるようにしました。それがbinary Unicode property of stringです。すごく長くて読みずらいので書記素プロパティと呼びます。

/\p{Basic_Emoji}/v.test('🖱️');// -> true
// ベーシックな絵文字
/\p{RGI_Emoji_Flag_Sequence}/v.test('🇯🇵');// -> true
// 国の文字にマッチ
全種類
コード 説明 説明
Basic_Emoji 単一のUnicodeコードポイントで表される基本的な絵文字。 😀,❤️,🔥
Emoji_Keycap_Sequence 数字や記号にキーキャップ記号を組み合わせた絵文字。 1️⃣,#️⃣
RGI_Emoji_Modifier_Sequence 絵文字の基本形に肌の色などの修飾子を加えたもの。 👍🏽,🙋🏿
RGI_Emoji_Flag_Sequence 地域を表すインジケーター記号を2つ組み合わせて国旗を表す絵文字。 🇺🇸,🇯🇵,🇫🇷
RGI_Emoji_Tag_Sequence タグ文字を使って特定の地域や意味を表す絵文字(例:海賊旗や州旗など)。 🏴‍☠️,🏴‍💻
RGI_Emoji_ZWJ_Sequence 絵文字同士をゼロ幅接合子(ZWJ)で繋いで1つの絵文字として表示するもの。 👨‍👩‍👧,🧑‍⚕️
RGI_Emoji 「一般的な利用が推奨される絵文字」。上記すべてのカテゴリを含む。 👩‍🚀,🏳️‍🌈,🐶

AI生成です。みんなが好きかは知りませんが僕は好きです。

[&&--\q{}]

(今のところ)三つの記号が追加されます。
a&&bはabどちらも当てはまるとマッチ、a--bはaに当てはまってbに当てはまらないものにマッチ\q{ab}はabという文字にマッチします。
まぁまったくわからないので例を出します。

let regex;

regex = /[\w&&a]/gv;
console.log('abc123'.match(regex));// a
// \wだけどaじゃないものにマッチ

regex = /[\w--[a13]]/gv;
console.log('abc123'.match(regex));// b, c, 2
// 新しく中に入れ子するのもあり

regex = /[\q{ac|ca}]/gv;
console.log('aca'.match(regex));// ac, ca
// \q{文字列|文字列|...}という形で使う。

さっきの書記素プロパティと合わせて使うと\q{}は本領を発揮します。

/[\p{RGI_Emoji_Flag_Sequence}--\q{🇺🇸}]/v.test('🇯🇵(日本)');// -> true
/[\p{RGI_Emoji_Flag_Sequence}--\q{🇺🇸}]/v.test('🇺🇸(アメリカ)');// -> false

こうすると🇺🇸以外の国にマッチするようになります。\q{}を使って一文字にまとめないとエラーになります。

その他

その他のその他とかふざけてんのかって怒るほどの文量はないので勘弁してね
エスケープ
エスケープしていい文字とダメな文字があります。こちらを参照して表が見えるまで下にめくってください。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Regular_expressions/Literal_character#%E8%A7%A3%E8%AA%AC

おしまい

疲れた。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?