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?

Regular Expression(正規表現)と フラグ

Posted at

Regular Expression(正規表現) / RegExpとは? 

RegExpは正規表現のためのJavaScriptの組み込みクラス。
リテラルでの表記とコンストラクタを利用した表記の2通りがある。
TypeScriptにはRegExp型があり、これはJavaScriptのRegExpオブジェクトを表す。

リテラル記法
/ で検索したい文字を囲み、最後にフラグを書く
const re = / ab+c / i ;

例)リテラル記法
const re = /0(8|9)0-[0-9]{4}-[0-9]{4}/g;
  • g(グローバルフラグ):文字列内のすべての一致を検索。最初の一致を見つけた後も、次の一致を検索し続ける
  • |(パイプ):「または」を意味し、括弧( )でグールプ化する事で、意図しないマッチを防ぐ
  • [0-9] :複数の文字のいずれか一つにマッチし、ハイフン( - )を使って範囲指定を使った記述を行える
  • { }:数字の桁数を指定できる。{4}で4桁を表し、[0-9]{4}とする事で4桁の数字
例)グローバルフラグ (.js)
const re = /a/g;
const str = "banana";
console.log(str.match(re)); // ["a", "a", "a"]
例)グローバルフラグ (.ts)
const re: RegExp = /a/g; // RegExp型を指定
const str: string = "banana";
console.log(str.match(re)); // ["a", "a", "a"]

コンストラクタ記法
RegExpコンストラクタに、
第1引数 → 検索したい文字、第2引数 → フラグ

  • 最初の引数に文字列のパターンを渡す場合
    const re = new RegExp('ab+c', 'i');

または、

  • 最初の引数に正規表現リテラルを渡す場合
    const re = new RegExp(/ab+c/, 'i');
例)コンストラクタ記法 (.js)
const re = new RegExp('a', 'g'); // 第1引数 → 検索したい文字、第2引数 → フラグ
const str = "banana";
console.log(str.match(re)); // ["a", "a", "a"]
例)コンストラクタ記法 (.ts)
const re: RegExp = new RegExp('a', 'g'); // RegExp型を指定
const str: string = "banana";
console.log(str.match(re)); // ["a", "a", "a"]
  • matchメソッド:
    → gフラグがある場合: 正規表現は文字列全体に対してマッチを繰り返し検索し、すべての一致を配列として返す
    → gフラグがない場合、最初に一致した部分を含む配列を返す(マッチが1回のみで ["a"]になる)
    → 一致しない場合、null を返す

:warning: コンストラクタ記法ではバックスラッシュの扱いに注意する

例)リテラル記法
const regexp_re = /0(8|9)0-\d{4}-\d{4}/g;

\ については、コンストラクタを利用する場合はふたつ書く必要がある

例)コンストラクタ記法
const regexp_con = new RegExp("0(8|9)0-\\d{4}-\\d{4}", "g");

JavaScriptでは文字列内でバックスラッシュ \ はエスケープ文字として使われる。
つまり、\\ と書くことで、1つのバックスラッシュ を表現する。

\ を文字列として検索したい場合「コンストラクタでは \\\\ と4文字書く必要がある

例)リテラル記法
// バックスラッシュを検索したい場合
const regexp_re = /\\/;  // 1つのバックスラッシュを検索するために正規表現で
console.log(regexp_re.test("\\hoge"));  // true
例)コンストラクタ記法
// バックスラッシュを検索したい場合
const regexp_con = new RegExp("\\\\"); // 文字列リテラル内で '\\' を表現
console.log(regexp_con.test("\\hoge"));  // true
  • new RegExp("\\\\") では、最初の \\ は JavaScriptの文字列リテラル内でバックスラッシュを表すために2つ必要。(文字列リテラル内でバックスラッシュをエスケープするため)
  • その後、正規表現内でバックスラッシュを表すためにさらにエスケープする必要があるため、合計で4つのバックスラッシュ(\\\\)が必要
  • testメソッド: 正規表現が文字列の中に1回でもマッチする場合(部分一致)にtrue を返す

どっちを使う?

  • コンストラクタ記法
    正規表現のパターンやフラグが 動的に決まる場合ユーザー入力をもとに正規表現を生成する場合、といった動的に検索する対象を切り替えたい場合
  • リテラル記法
    正規表現のパターンが事前に決まっている様な場合、特に理由がない場合

フラグ

g: global
g
検索はすべての一致を探す。ただし、gの指定がない場合は、最初の1つのみを探す。
const text = "123 abc 456 789";
const regex = /\d+/g;
const matches = text.match(regex);
console.log(matches);  // ["123", "456", "789"]
  • \d: 半角の数字 (digit)
  • +: 1 回以上の繰り返し
  • matchメソッド: 正規表現に一致したすべての部分を配列で返し、なければ null を返す

i: ignoreCase
i
正規表現を検索する際、大文字小文字を区別ぜず検索を行う。
const msg = "Hello, World!";
const pattern = /WORLD/i; // i フラグは大小区別しない
const isMatch = pattern.test(msg);
console.log(isMatch); // true
  • testメソッド: 正規表現が文字列の中に1回でもマッチする場合(部分一致)にtrue を返す

m: multiline
m
対象の文字列が複数行の場合、特定の文字列パターンの検索を行う。
行の開始 (^) や行の終了 ($) が各行の先頭や末尾にマッチするようになる。
const text = `Hello
World
Goodbye
World`;

const mLineStart = /^Hello/m; // ^ 行の開始 各行の先頭にマッチ
const mStart = text.match(mLineStart);
console.log(mStart); // ['Hello']

const mLineEnd = /World$/m; // $ 行の終了 各行の末尾にマッチ
const mEnd = text.match(mLineEnd);
console.log(mEnd);  // 2行目と4行目がWorldで終わっているため、["World", "World"]
  • matchメソッド: 正規表現に一致したすべての部分を配列で返し、なければ null を返す

s: dotAll
s
正規表現のドット(.)が改行文字(\n)にもマッチするようにするフラグ。
→ 正規表現におけるドット (.) は、通常、任意の1文字を表すが、改行文字 (\n) にはマッチしないため
改行文字 (\n)がない場合
const sentence = "father I will always be with you";
const regex = /father.*/you/;
console.log(regex.test(sentence));  // true
  • .: 任意の1文字
  • *: 直前の要素が0回以上繰り返される(直前の文字がない or 直前の文字が1個以上連続する)
  • .*: 任意の文字が0回以上繰り返される(何でもいい文字の連続)
  • testメソッド: 正規表現が文字列の中に1回でもマッチする場合(部分一致)にtrue を返す
改行文字 (\n)がある場合
const sentence = "I am your father.\nI will always be with you."; // 改行文字を含む
const regex = /father\..*you\./;  // sフラグ未使用
console.log(regex.test(sentence));  // false
  • \.: リテラルのドット(.)にマッチ

.: 正規表現におけるドット (.) は、改行文字(\n)にはマッチしない
.*は改行を含まない任意の文字列にマッチするため、改行があると一致しない)

改行文字 (\n)がある場合、sフラグを使用
const sentence = "I am your father.\nI will always be with you."; // 改行文字を含む
const regex = /father\..*you\./s; // sフラグ使用
console.log(regex.test(sentence)); // true

s フラグを使用すると、改行文字(\n)が含まれていても、正規表現のドット (.) でマッチするようになる


u: unicode
u
マルチバイトの Unicode 文字を正しく扱うことができる
const regex = /\u{61}/u;  // `u` フラグ付き
console.log(regex.test("a"));  // true("a" は Unicode コードポイント 0x61 に一致する)
console.log(regex.test("b"));  // false("b" は一致しない)

// `u`フラグなし
const regex = /\u{61}/; // "u" が 61 回連続する文字列
console.log(regex.test("u".repeat(61))); // true("u" を 61 回繰り返した文字列は一致する)
  • \u{xxxx} は Unicodeコードポイント を指定する方法で、{} の中にコードポイントを16進数で書く(xxxxの部分)

  • /\u{61}/u: Unicodeコードポイント U+0061 を指し、"a" に一致

  • \u: 単なる文字 u として扱われる(\u{61} は u{61} と同じ解釈)

  • {num}: 直前のパターンのnum回繰り返し

例1) \u0041 
→ Unicodeコードポイント U+0041 を示し、「A」を表す。 
  {} を使わない形式もあり、4桁のコードポイントでよく見られる。
例2)
const regex = /^u{61}$/;  // 文字「u」を61回繰り返す文字列に一致
console.log(regex.test("u".repeat(61)));  // true
例3)
const regex = /u{61}/; // 文字「u」を61回繰り返す文字列に一致
console.log(regex.test("u".repeat(61)));  // true

y : sticky
y
RegExp オブジェクトの lastIndex プロパティが示す位置からのみマッチするかどうかを調べる。
const adress = "東京都中央区銀座";

// yフラグを使用しない場合
const regex = /中央区/;
console.log(regex.test(adress)); // true

// yフラグを使用した場合
const regexY = /中央区/y; // 粘着検索フラグ
//console.log(regexY.lastIndex); // デフォルト 0
console.log(regexY.test(adress)); // false
//console.log(regexY.lastIndex); // 0
console.log(regexY.test(adress)); // false
  • testメソッド: 正規表現が文字列の中に1回でもマッチする場合(部分一致)にtrue を返す
  • lastIndex: 次に検索を開始すべき位置を示す

yフラグを使用すると、

  • 1 回目の検索:lastIndex が示す位置から始まり、最初の検索では、lastIndex は 0 で、文字列の先頭から検索を始める。文字列 "東京都中央区銀座" の最初の部分は "東京都" で、"中央区" は最初には一致しないため、結果、falseを返す

  • 2 回目の検索:前回一致しなかったため、lastIndex はリセットされ、そのまま 0 になる。そのため、検索は再び最初の位置(lastIndex = 0)から始まり、再度 "中央区" を見つけられないため、false を返す

lastIndexの位置の変更を加えてみると、以下の様に2回目の検索は trueになる。

const regexY = /中央区/y; // 粘着検索フラグ
//console.log(regexY.lastIndex); // デフォルト 0
console.log(regexY.test(adress)); // false
regexY.lastIndex = 3;
console.log(regexY.test(adress)); // true

参考

0
0
1

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?