🔙
🔝

【paiza問題集 解説】
正規表現メニュー

エスケープシーケンスの検索

エスケープシーケンスの検索

STEP: 1 文字列の検索

文字列の検索

    import re
    
    S = input()
    
    pattern = re.compile(r"paiza")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    

    まず、正規表現を扱えるようにする為に import re を冒頭に書きます。

    次に、正規表現を書きます。正規表現は raw文字列 というものを使います。

    r""
    

    という書き方をします。通常の文字列で使う ' " の前に r を書き加えるだけです。
    ここでは以降、一律して r"" と書くこととします。
    ここに検索したい文字列を記述します。この問題は「'paiza' を見つけてその位置番号返す」ことが求められていますので r"paiza" と記します。正規表現を使って書かれたこの形のものを「パターン (pattern)」と言います。

    次にこのパターンを使って、入力 S の中にパターンに指定した文字列があるかどうかを調べます。re.search(pattern, S)
    これを試しに画面に出力してみると、

    <re.Match object; span=(8, 13), match='paiza'>

    と検索結果(オブジェクト)の中身が表示されます。span=(8, 13), match='paiza' は「文字列の 8 番目から 12 番目に 'paiza' があります。」という意味です。'paiza' の一文字目の p が 8 番目、五文字目の a が 12 番目です。range() と同じ範囲の示し方ですね。
    正規表現では検索文字列を見つけた場合を、マッチしたと表現します。

    最後の print() 関数でメソッドが使われています。

    メソッド 機能
    .group() マッチした文字列を返す。()内はグループ番号。
    .span() マッチした文字列の範囲をタプルで返す。
    .start() マッチした文字列の開始位置番号を返す。
    .end() マッチした文字列の末尾の位置番号 +1 を返す。

    グループというのはまたこの後の該当する問題で説明されます。これを使ってマッチした文字列を画面に表示させたり、その他、文字列としていろいろ使用したりできます。

    この問題では開始位置を画面に出力するよう求めています。.start() メソッドを使えば一丁上がりです。ただこれでは文字列の .find() メソッドと変わりありません。次の問題からがいよいよ正規表現らしいパターンの書き方が登場します。

    pattern = re.compile(r"paiza")
    

    compile() 関数は、このパターンを何度も使う時に予め変数に入れておき、使うたびにパターンを作らなくて済むようにする為に書かれます。

    pattern = r"paiza"
    re_matched = re.search(pattern, S)  # 関数
    

    と書いたり、

    re_matched = re.search(r"paiza", S)
    

    と単体で書くこともできますが、いずれもその場で都度パターンを作る処理をしています。
    また、コンパイルしたパターンに限り、

    pattern = re.compile(r"paiza")
    re_matched = pattern.search(S)  # メソッド
    

    という書き方ができます。

    以降のプログラム例では一回しか使わなくても、見慣れる為に compile() 関数を使ってコンパイルしたものを使っていきます。
    普段は少ししか使わないときはコンパイルする必要はありません。
    って、この人が言ってました。

STEP: 2 メタ文字の検索

メタ文字の検索

    import re
    
    S = input()
    
    pattern = re.compile(r"\\\(\^ \. \^\)/")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    

    .*+?^$|(){}[]\ の出現文字の前にバックスラッシュ \ をつければ文字として認識されるようになります。この一覧に書かれている記号は、以降に正規表現として特別な意味を持つものとなっています。いきなりこれらの記号だけ憶えようとしても覚えられませんが、問題を進めていくことで少しずつ意味がわかるようになっていきます。

STEP: 3 任意文字の検索

任意文字の検索

    import re
    
    S = input()
    
    pattern = re.compile(r"p..za")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    

    . はすべての1文字を受け入れます。これをワイルドカードと言います。カードゲームのポーカーが由来の用語です。

    問題に『任意の 1 文字が 2 回続き』とありますので、適所を .. とするだけです。こうするとこの2文字は、アルファベットや数字、記号、また日本語文字などのどんな文字も受け入れます。全角文字も半角文字と同様に1文字として数えられます。

STEP: 4 クラス指定文字の検索

クラス指定文字の検索

    import re
    
    S = input()
    
    pattern = re.compile(r"Math[123][ABC]")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    

    [] の中に書かれた文字のいずれか1文字がマッチした時にマッチとなります。
    . はすべての文字を受け入れますが、その文字を限定したものが [] となります。複数使うと組み合わせになります。[123][ABC] を例にすると、

    1A, 1B, 1C, 2A, 2B, 2C, 3A, 3B, 3C

    のいずれか1つとマッチします。

STEP: 5 クラスの否定の検索

クラスの否定の検索

    import re
    
    S = input()
    
    pattern = re.compile(r"[^0123456789].....")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    

    今度は受け入れない文字を指定する否定です。半角数字なので、0 ~ 9 を羅列すればOKです。
    また 0 ~ 9 の半角数字は \d で表すこともできますので、r"[^\d]....." と書くこともできます。

STEP: 6 範囲指定文字の検索

範囲指定文字の検索

    import re
    
    S = input()
    
    pattern = re.compile(r"[A-Z]-[0-9][0-9][a-z]")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    

    [] の中ではハイフン - で文字の範囲を指定することができます。自由に範囲を指定できるので、[C-F] [0-9a-f]という使い方もできます。

    注意点として、この文字は unicode のコード番号の「小さい数 → 大きい数」の順に並んでいなくてはいけません。[Z-A] とするとエラーとなります。また、[A-z] とすると、Za の間にある記号 [\]^_` まで含まれてしまいます。この場合は [A-Za-z]と分けて書くことで回避できます。

STEP: 7 0 回または 1 回の出現の検索

0 回または 1 回の出現の検索

    import re
    
    S = input()
    
    pattern = re.compile(r"clang-?format")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    

    0 回か 1 回かは、その文字が「ある時ない時関わらず」マッチします。clang-?format では、 clang-format clangformat どちらにもマッチしますが、clang--format にはマッチしません。

STEP: 8 0 回以上の繰り返しの検索

0 回以上の繰り返しの検索

    import re
    
    S = input()
    
    pattern = re.compile(r"congratulations!*")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    

    *? のリミットブレイク版です。0 個でも何個あってもマッチします。よって r".*" とするとどんな文字列にもマッチします。イミナシ

STEP: 9 1 回以上の繰り返しの検索

1 回以上の繰り返しの検索

    import re
    
    S = input()
    
    pattern = re.compile(r"ID-[0-9]+")  # r"ID-\d+" も可
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    

    この + は、1つも無い時にはマッチしないので、数となりうる数字を探す時に特に便利に使えます。

STEP: 10 指定回数の繰り返しの検索

指定回数の繰り返しの検索

    import re
    
    S = input()
    
    pattern = re.compile(r"CVE-[0-9]{4}-[A-Za-z0-9]+")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    

    ..... と書かなくても、.{5} と数を記すだけでよくなります。たとえ、数字 1024文字に固定したい場合でも [0-9] を 1024個書かなくても [0-9]{1024} と書くだけで済みます。

STEP: 11 下限指定の繰り返しの検索

下限指定の繰り返しの検索

    import re
    
    S = input()
    
    pattern = re.compile(r"To be continued\.{3,}")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    

    ここで注意すべきは . の前にバックスラッシュ \ を付けないと異なる結果となる恐れがあります。きちんと \ を付けて、文字のピリオド . と認識させましょう。😉

STEP: 12 上限指定の繰り返しの検索

上限指定の繰り返しの検索

    import re
    
    S = input()
    
    pattern = re.compile(r"database_.{,5}\.db")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    

    下限が上限になっただけですので特筆すべきことはありませんし、. の前にバックスラッシュ \ を付けるのをまた忘れた方は反省してこれからは気を付けてください。😊

STEP: 13 範囲指定の繰り返しの検索

範囲指定の繰り返しの検索

    import re
    
    S = input()
    
    pattern = re.compile(r"\$[0-9]{3,5}")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    

    $ はメタ文字ですのでバックスラッシュ \ を付ける必要があります。

STEP: 14 OR の検索

OR の検索

    import re
    
    S = input()
    
    pattern = re.compile(r"accept|reject|pending")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    

    単体で使う場合はこのようにして書きます。他の文字が混ざる時には、次の問題の様な書き方をします。

STEP: 15 グループを利用した OR の検索

グループを利用した OR の検索

    import re
    
    S = input()
    
    pattern = re.compile(r"[^ ]*(\.jpg|\.png)")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    

    複雑になってきましたね。😓
    グループは ()を付けられた順に番号が振られています。このパターンで言うと、

    グループ 0 … [^ ]*(\.jpg|\.png)
    グループ 1 … (\.jpg|\.png)

    となっています。グループ 1 以降を作らなくても、常に全体がグループ 0 となっています。また前半も () で囲うと、

    r"([^ ]*)(\.jpg|\.png)"

    グループ 0 … ([^ ]*)(\.jpg|\.png)
    グループ 1 … ([^ ]*)
    グループ 2 … (\.jpg|\.png)

    となります。これは .group() メソッドの引数にグループ番号を与えると、マッチしたグループの文字列が抽出されます。

    例)<re.Match object; span=(8, 13), match='paiza'>

    print(re_matched.group())
    
    paiza引数省略時は グループ 0
STEP: 16 グループを用いた繰り返しの検索

グループを用いた繰り返しの検索

    import re
    
    S = input()
    
    pattern = re.compile(r"(%[A-Za-z0-9]{2}){2,}")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    

    プログラムの ( ) と同じ様な使い方になりますので、使い方がわかれば特に疑問無く使えるかと思われます。

STEP: 17 行頭の検索

行頭の検索

    import re
    
    S = input()
    
    pattern = re.compile(r"^(Re:)")
    re_matched = re.search(pattern, S)
    
    if re_matched:
        print('Yes')
    else:
        print('No')
    

    キャレット ^ は、常に先頭に配置されます。

    今度は位置を示すのではなく、判定結果を画面に出力するよう求められています。
    re.search() でマッチした文字列を見つけると、

    <re.Match object; span=(0, 3), match='Re:'>

    が返りますが、マッチした文字列が見つからなかった場合は None が返ります。
    その性質を利用して、re_matched に値があるかないかで判定できます。

STEP: 18 行末の検索

行末の検索

    import re
    
    S = input()
    
    pattern = re.compile(r"\\\(.*\\\)$")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    

    あれ?これ合ってるよね?😅 ワカラナクナッテキタ
    $ は常に行末に配置されます。

FINAL問題 エスケープシーケンスの検索

エスケープシーケンスの検索

    import re
    
    S = input()
    
    pattern = re.compile(r"\w{3}-\d{3,4}")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    

    問題内に紹介されているエスケープシーケンス一覧はメモしておいたほうがいいです。私は OneNote にメモして忘れた時に見ています。

文字列の分割

文字列の分割

STEP: 1 文字列の検索

文字列の検索

    import re
    
    S = input()
    
    pattern = re.compile(r"[a-f\d]{64}")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    print(re_matched.group())
    

    マッチした文字列を扱う場合は .group() メソッドを使います。

STEP: 2 文字列の全検索

文字列の全検索

    import re
    
    S = input()
    
    pattern = re.compile(r"\S+@\S+")
    re_matched = re.findall(pattern, S)
    
    print(*re_matched, sep='\n')
    

    全検索には .findall() メソッドを使います。これはマッチした全ての文字列をそれぞれ要素にしてリストで返します。

    半角スペースは \s、半角スペース以外\S と、大文字で書きます。

STEP: 3 文字列の置換

文字列の置換

    import re
    
    S = input()
    
    pattern = re.compile(r"(\d{2})(\.)(\d{2})")
    re_match = re.sub(pattern, r"\g<1>/\g<3>", S, count=1)
    
    print(re_match)
    

    置き換えは sub() 関数を使います。第二引数にマッチした文字列から置き換えたい文字を指定します。

    パターンをグループ別にすると、

    グループ 0 … \d{2}\.\d{2}
    グループ 1 … \d{2} (前)
    グループ 2 … \.
    グループ 3 … \d{2} (後)

    となっています。
    第二引数の置き換え文字の中で、マッチした時にこのグループを指定して扱うことができます。

    \g<1> … グループ 1 に置き換える
    / ……… / に置き換える
    \g<3> … グループ 3 に置き換える

    12.01 にマッチした場合、

    グループ 1 … 12
    グループ 2 … ./
    グループ 3 … 01

    結果、12/01 と置き換えられます。

    count=1 というのは、複数マッチした場合、先頭から数えて 1 回だけ置き換えるように回数を制限しています。paiza の解答コード例では count=1 のキーワードを省略していますが、キーワードは省略しないことをお奨めします。

    グループ番号の指定では \g<1> の代わりに \1 と書くこともできます。こちらのほうが簡潔に書けてよいのですが、この後に数字、例えば 0 と続いた場合に \10 となり、グループ 10 と認識されてしまいます。そこまでグループ数が多くなることは稀かと思われますが、今回はどちらにも対応できる \g<1> という書き方をしました。\1 と書くほうが一般的なのですが、お好みでどうぞ。😸


    ちなみに \. に ( ) は不要なのですが、説明の為にグループ化しました。

    pattern = re.compile(r"(\d{2})\.(\d{2})")
    re_match = re.sub(pattern, r"\g<1>/\g<2>", s, count=1)
    

    でOK!

STEP: 4 文字列の全置換

文字列の全置換

    import re
    
    S = input()
    
    pattern = re.compile(r"raw_input")
    re_matched = re.sub(pattern, r"input", S)
    
    print(re_matched)
    

    こちらは無条件に全部置き換えます。こちらを先にやるべきではなかったのかと思うのですが。😓
    'input' のように、文字列のみの場合は raw文字列でなくても問題ありません。

    パターンを raw_ とだけして置き換え文字を '' としてしまうと input と続かないところまで置き換えてしまいますので、きちんと raw_input と指定しましょう。

STEP: 5 文字列の削除

文字列の削除

    import re
    
    S = input()
    
    pattern = r"/\*.*\*/"
    re_match = re.sub(pattern, r"", S)
    
    print(re_match)
    

    置き換え文字をヌルストリング (null string) にするだけで対象の文字列を削除することができます。

    ヌルストリングとは、何も入っていない文字列(空の文字列)のことです。

    r"" の代わりに '' でも可です。

STEP: 6 文字列の全削除

STEP: 6 文字列の全削除

    import re
    
    S = input()
    
    pattern = re.compile(r"import \w+")
    re_matched = re.sub(pattern, r"", S)
    
    print(re_matched)
    

    \w を使うと半角英数字の他にアンダースコア _ も含まれます。アンダースコアが含まれてはいけない場合には \w[^_]+ と書きます。

FINAL問題 文字列の分割

文字列の分割

    import re
    
    S = input()
    
    pattern = re.compile(r"---")
    re_matched = re.split(pattern, S)
    
    print(*re_matched, sep='\n')
    

    split() 関数を使うと、パターンを区切り文字として分割し、リストにして返します。

否定後読み

否定後読み

STEP: 1 最短一致と 0 回または 1 回の繰り返し

最短一致と 0 回または 1 回の繰り返し

    import re
    
    S = input()
    
    pattern = re.compile(r"G[A-Z]??C")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    print(re_matched.group())
    

    デフォルトでは「最長一致」と言って、?+*{} を指定した時、できる限り長い文字数でマッチしますが、「最短一致」ではできる限り短い文字数でマッチします。

STEP: 2 最短一致と 0 回以上の繰り返し

最短一致と 0 回以上の繰り返し

    import re
    
    S = input()
    
    pattern = re.compile(r"\{.*?\}")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    print(re_matched.group())
    

    デフォルトでは「最長一致」と言って、?+*{} を指定した時、できる限り長い文字数でマッチしますが、「最短一致」ではできる限り短い文字数でマッチします。

STEP: 3 最短一致と 1 回以上の繰り返し

最短一致と 1 回以上の繰り返し

    import re
    
    S = input()
    
    pattern = re.compile(r"#.+?\s")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    print(re_matched.group())
    

    デフォルトでは「最長一致」と言って、?+*{} を指定した時、できる限り長い文字数でマッチしますが、「最短一致」ではできる限り短い文字数でマッチします。

STEP: 4 最短一致と指定回数の繰り返し

最短一致と指定回数の繰り返し

    import re
    
    S = input()
    
    pattern = re.compile(r"\|.{3,10}?\|")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    print(re_matched.group())
    

    デフォルトでは「最長一致」と言って、?+*{} を指定した時、できる限り長い文字数でマッチしますが、「最短一致」ではできる限り短い文字数でマッチします。


    手抜き説明はここまで。😉👌

STEP: 5 キャプチャとその回避

キャプチャとその回避

    import re
    
    S = input()
    
    pattern = re.compile(r"(?:n|st|vac)ation([A-Za-z0-9]+)")
    re_matched = re.search(pattern, S)
    
    print(re_matched.group())
    print(re_matched.group(1))
    

    キャプチャの意味は問題の中で説明されているとおりです。グループ化目的でない ( ) をグループとして認識させないようにする時に (?:) を使います。「これ、グループじゃないよ」というコメントみたいなものです。

    一応、グループには任意に名前を付けたりすることもできます。

    (?P<name>) … name の所に任意の名前を付ける

    
        ID=012345
    
    import re
    
    S = input()
    
    pattern = re.compile(r"ID=(?P<num>\d{6})")
    re_matched = re.search(pattern, S)
    
    print(re_matched.group())
    print(re_matched.group(1))
    print(re_matched.group('num'))
    print(re_matched['num'])
    
    ID=012345… グループ 0 012345… グループ 1 012345… グループ num 012345… グループ num

    グループに名前を付けたからといってグループ番号が使えなくなるということはありません。どちらの方法でも指定のグループにアクセスできます。

STEP: 6 肯定先読み

肯定先読み

    import re
    
    S = input()
    
    pattern = re.compile(r"\d+(?=KB|MB|GB|TB)")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    print(re_matched.group())
    

    マッチの対象となる単位をマッチ後に除外していますので、グループ 0 で画面に出力しても数字部分のみしか表示されません。

STEP: 7 否定先読み

否定先読み

    import re
    
    S = input()
    
    pattern = re.compile(r"Java(?!Script)")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    print(re_matched.group())
    

    マッチした文字列の後ろに (?!) で指定した文字列が続く時、この文字列にはマッチしません。

    問題の入力例では、Java にはマッチしますが、Java の後に Script が続く JavaScript にはマッチしません。

STEP: 8 肯定後読み

肯定後読み

    import re
    
    S = input()
    
    pattern = re.compile(r"(?<=Date: )[\d/]+")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    print(re_matched.group())
    

    (?<=) で指定した文字列が直前にある時のみマッチします。
    「肯定先読み」の前にあるバージョンです。

    ちなみに私はこういった用語や頻繁に使う記号以外はあまり記憶していません。自分なりにまとめたチートシートを見て参照しながらパターンを作っています。使っているとジョジョに覚えていきますが、使わなくなると途端に忘れます。ですので、OneNote様様です。

FINAL問題 否定後読み

否定後読み

    import re
    
    S = input()
    
    pattern = re.compile(r"(?<!\[Feature\] )[A-Z][^[\]]{2,}?\.")
    re_matched = re.search(pattern, S)
    
    print(re_matched.start())
    print(re_matched.group())
    

    ┐(´‐`)┌ サブウoイカョ...

正規表現まとめ

正規表現まとめ

    メタ文字 .*+?^$|(){}[]\
    キャプチャ ((ex)pr)ession 0:expression 1:ex 2:expr

    記号 ESC 機能
    \ \\ メタ文字をエスケープ。
    . \. 1文字とマッチ。ワイルドカード。\nのみ例外で不一致。
    ^ \^ 文字列の先頭にマッチ。
    $ \$ 文字列の末尾にマッチ。
    [] \[ \] 文字の集合。[ABC]は'A', 'B', 'C'のいずれかにマッチ。
    []内はメタ文字が \]^- の4文字に限定される。
    [^] \^ 否定。(not , ! の意) [^A]で'A'以外の1文字にマッチする。
    [-] \- 文字の範囲指定。[A-Za-z0-9]で英数字の1文字とマッチする。
    ? \? 直前の文字(列)が 0~1回出現でマッチする。
    * \* 直前の文字(列)が 0回以上出現でマッチする。
    + \+ 直前の文字(列)が 1回以上出現でマッチする。
    {}
    {,}
    {m,n}
    \{ \} 直前の文字(列)が {n回}出現でマッチする。
    直前の文字(列)が {m回以上} {n回以下}出現でマッチする。
    直前の文字(列)が {m~n回}出現でマッチする。
    ??, +?, *?
    {m,n}?
    最短一致。非貪欲。(non-greedy)
    直前の文字(列)で、最短回数の文字(列)にマッチする。
    ?*, +*, **
    {m,n}*
    最長一致。(デフォルト)
    上記の最長回数にマッチする。
    | \| バーティカルバーで区切られた文字列のいずれかとマッチする。
    () \( \) グループ化。各メタ文字などと組み合わせ可能。
    \1 \2 …
    \g<1> \g<2>
    グループ番号。
    (?:) キャプチャ回避。(?:pre|post)fix 0:prefix 1:なし
    (?=) 肯定先読み。/d+(?=円) "100円 200ドル 300ユーロ"
    100円の 100 にマッチ。円以外はマッチしない。
    (?=)内の文字列に一致しても(?=)内の文字列はマッチさせない。
    (?<=) 肯定後読み。(?<=円:)\d+ "円:100 ドル:200 ユーロ:300"
    円:100 の 100 にマッチ。
    (?!) 否定先読み。そろばん(?!ど) "そろばんでそろばんど"
    そろばんでの そろばん にマッチ。そろばんどはマッチしない。
    (?!)内の文字に一致しない時だけ直前の文字列にマッチさせる。
    (?<!) 否定後読み。(?<!県)..市 "大阪府大阪市 神奈川県横浜市"
    大阪府大阪市の 大阪市 にマッチ。神奈川県横浜市はマッチしない。
    (?P<'key'>) グループに一意のキーを付ける。
    re_matched.group('key')
    re_matched['key'] バージョン3.6

    re.compile(pattern) 正規表現オブジェクトにコンパイルする。
    変数に格納してパターンを再利用できるようにする。
    pattern = re.compile(r"\d+")
    re.search(pattern, str) str文字列から正規表現patternを使って最初に見つかった文字列を取得する。

    re_match = re.search(pattern, str)
    re_match.group() マッチした文字列を返す。()内はグループ番号。
    re_match.start() マッチした文字列の開始要素番号。
    re_match.end() マッチした文字列の末尾の要素番号+1。

    re.findall(pattern, str) マッチしたすべての文字列をリストで返す。
    re.match(pattern, str) strの先頭でのみマッチした文字列を返す。
    re.fullmatch(pattern, str) str文字列すべてにマッチしたら(strと同じ)文字列を返す。
    re.sub(pattern, repl, str) 正規表現パターンにマッチした文字列をreplに置き換える。
    re.split(pattern, str, maxsplit=0) 正規表現パターンにマッチした文字列で分割する。

    \d 半角数字1文字
    \D 上記以外の1文字
    \s 空白文字1文字。(スペース, タブ, 改行)
    \S 上記以外の1文字。
    \w 半角英数字記号1文字。
    \W 上記以外の1文字。
    \n 改行文字。
    \t タブ文字。
    \A 文字列の先頭。
    \Z 文字列の末尾。