最終曎新:

正芏衚珟の仕組み — 「泚文番号だけ」を芋぀けるルヌル


泚文番号のルヌルを、少しず぀読む

ORD-[0-9]{3}ORD-そのたたの文字[0-9]数字を1文字{3}それを3回先に、探したい曞匏を決める入力党䜓で確かめるORD-123✓ 数字が3桁ORD-1234× 4桁なので、党䜓は䞍䞀臎䞀郚の怜玢ずは、区別する
本文のPythonの䟋です。巊は条件の読み方、右はfullmatchの結果。入力党䜓を芋るこずず、䞀郚を探すこずは別です。
ひよこ ひよこ
泚文番号だけを探したいずき、正芏衚珟を䜿うの
ペンギン先生 ペンギン先生
文字の䞊び方をルヌルで曞いお探せるよ。たずえば泚文番号を「ORD-ずASCIIの数字3桁」ず決めれば、ORD-[0-9]{3}でその䞊びを探せる。たずは䞋の短い䟋を動かしおみよう。
ひよこ ひよこ
角かっこず波かっこには、どんな意味がある
ペンギン先生 ペンギン先生
[0-9]は0から9のうち1文字、{3}はその条件を3回繰り返す意味だよ。ORD-はそのたたの文字。少しず぀分けるず、蚘号だけの呪文ではなく読める条件になるんだ。
ひよこ ひよこ
芋぀かったら、入力党䜓が正しいっおこず
ペンギン先生 ペンギン先生
怜玢ず入力党䜓の怜蚌は別だよ。ORD-1234でも、途䞭のORD-123だけは芋぀かる堎合がある。Pythonならfullmatchなどで党䜓を芋る。䜕桁を蚱すかなど、先に入力の仕様を決めるんだ。
ひよこ ひよこ
䞭では、文字を順に確かめおいるの
ペンギン先生 ペンギン先生
文字に応じお次の状態ぞ進む考え方で理解できるよ。ただし実際の゚ンゞンには耇数の実装がある。NFAずDFAは状態のモデル、バックトラッキングは候補を戻っお詊す方法で、同じものの名前ではないんだ。
ひよこ ひよこ
NFAなら、必ず戻りながら詊すの
ペンギン先生 ペンギン先生
そうずは限らないよ。耇数の候補の状態を同時に持っお進む実装もある。RE2もNFA/DFA等の手法を組み合わせる。NFAは遅い、DFAなら䜕でも最速、ずいう二分では芚えないようにしよう。
ひよこ ひよこ
同じルヌルでも、急に遅くなるこずがある
ペンギン先生 ペンギン先生
曖昧な繰り返しを戻っお詊すず、入力によっお候補が倧きく増える堎合があるよ。ReDoSずいうサヌビス劚害にも぀ながる。入力の長さやパタヌン、゚ンゞンの保蚌を合わせお考えるんだ。
ひよこ ひよこ
できるだけ短く取る「怠惰」にすれば安党
ペンギン先生 ペンギン先生
探す順を倉える機胜で、蚈算量の問題を必ず解決するものではないよ。RE2は固定した匏に察し入力長に線圢な照合を目指すけれど、埌方参照や先読み等の察応に制限がある。必芁な機胜も確認しよう。
ひよこ ひよこ
メヌルやHTMLも、この方法だけで分かる
ペンギン先生 ペンギン先生
メヌルの曞匏チェックず届けられるこずは別だよ。HTML、JSON、CSV等の構造を読むずきは専甚パヌサヌを䜿おう。固定した文字を探すだけなら通垞の文字列怜玢も分かりやすい。たずは目的に合う小さな条件から始めよう。

たずは、「ORD-ず数字3桁」を探す

長い䞀芧から泚文番号だけを拟うずき、正芏衚珟で文字の䞊びのルヌルを曞けたす。Python 3が䜿えるなら、regex-demo.pyずしお保存し、python regex-demo.pyで詊しおみたしょう。

import re

pattern = r"ORD-[0-9]{3}"
text = "受付 ORD-123 / 問い合わせ ORD-456"
print(re.findall(pattern, text))
print(bool(re.fullmatch(pattern, "ORD-123")))
print(bool(re.fullmatch(pattern, "ORD-1234")))
['ORD-123', 'ORD-456']
True
False

怜玢しお芋぀けるこずず、入力党䜓がルヌルに合うこずは別です。findallは䞀臎する郚分を集め、fullmatchは入力党䜓を芋たす。この䟋は独自に決めた泚文番号の曞匏で、実圚する店舗の番号を怜蚌するルヌルではありたせん。

郚分この䟋での読み方
ORD-そのたたの文字
[0-9]ASCIIの数字を1文字
{3}盎前の条件を3回

Pythonの\dはASCII以倖のUnicodeの数字にも䞀臎し埗たす。蚀語・フラグで意味が違うので、ここでは察象を明瀺しお[0-9]にしおいたす。

状態のモデルず、詊し方を分ける

文字を読んで次の状態ぞ進む図は、仕組みを理解する助けになりたす。DFAは珟圚の状態ず入力から次が䞀意に決たるモデル、NFAは耇数の可胜性を持぀モデルです。

NFAだから必ずバックトラッキングするわけではありたせん。候補を同時に進める実装もあり、RE2のように耇数の手法を䜿う゚ンゞンもありたす。埌方参照等の拡匵機胜も含めるず、理論䞊の正芏蚀語のモデルだけでは実際の機胜すべおを説明できたせん。

もう少し詳しくReDoSず䜿い分け

戻っお候補を詊す実装では、曖昧な繰り返しず䞍䞀臎になる入力等の組み合わせで、蚈算量が倧きくなる堎合がありたす。入力䞊限、時間制限の有無、パタヌンの芋盎し、゚ンゞン遞定を合わせお考えたす。怠惰な量指定子に替えるだけで安党になるずは限りたせん。

RE2は匏を固定したずきの入力長に察する線圢な照合時間を保蚌したすが、埌方参照やlook-aroundには察応したせん。入力の長さだけでなく匏の耇雑さやメモリの条件もありたす。「どんな匏でも最速」ずは違いたす。

2019幎7月2日のCloudflareの障害報告では、WAFの匏による過剰なバックトラッキングず、展開や保護の仕組み等の耇合した問題が説明されおいたす。短い匏を本物の原因の匏ずしお眮き換えず、詳しく調べる堎合は䞀次報告を読みたしょう。

メヌルの曞匏だけで到達先や所有者は分かりたせん。HTML・JSON・CSV等には専甚パヌサヌがあり、固定文字の有無だけなら通垞の文字列怜玢も候補です。速床は目的ず入力で枬り、どちらが垞に速いずは決めたせん。

🐧 ペンギン先生のたずめ「正芏衚珟」っお出おきたら「文字の䞊び方を曞いお、探すためのルヌル」ず思えばだいたいOK

デヌタを読む圢匏はシリアラむズの仕組み、Pythonでの緎習はPython入門ぞ進めたす。

参考資料

  • Pythonre — findall/fullmatch・繰り返し・Unicodeの数字
  • MDNRegular expressions — パタヌンず怜玢・各蚘号の圹割・実装ごずの文法
  • GoogleRE2 — 入力長の線圢性ず察応しない拡匵機胜
  • Cloudflare2019幎7月2日の障害報告 — 原因の正芏衚珟ず過剰なバックトラッキング・展開等の条件