正規表現で全てのマッチを探すことは、常に O(n²) でした。

2026/03/20 3:40

正規表現で全てのマッチを探すことは、常に O(n²) でした。

RSS: https://news.ycombinator.com/rss

要約

日本語訳:

主旨
一般的な正規表現エンジンは、単一のマッチに対してのみ線形時間を保証し、そのイテレータはパターンと文字列が信頼できない場合、最悪ケースで (O(m \cdot n^{2})) あるいは指数関数的な爆発(ReDoS 攻撃)を起こす可能性があります。

重要性
二次的な爆発は、バックトラッキングが各位置で多くの枝を試すために発生します(例:長い「b」文字列上の

.*a|b
)。バックトラッキングエンジンは指数関数的になることもあります。Thompson の NFA 構築法ではそれを回避できますが、ほとんどのライブラリはデフォルトでバックトラッキングを採用しています。

記事の提案
RE# は二段階アルゴリズムを実装しています:逆方向 DFA が (O(n)) 時間で全ての潜在的開始位置を見つけ、前方 DFA が左端長いマッチを選択し、POSIX の意味論を保持します。強化モードでは、前方パスを活性状態に対する (O(n \cdot S)) スキャンで置き換え、

.*a|b
のような悪質なパターンでも長い「b」文字列上で線形時間を保証します。

主な利点

  • 任意の正規表現に対して全マッチが線形時間で取得できる。
  • 強化モードは安全性を保証し、典型的なワークロードではわずかな遅延(約 3–20 倍)しか生じません。
  • 大規模な交互辞書に対して Aho–Corasick を上回る性能を発揮します。RE# は小さくキャッシュフレンドリーな派生 DFA を遅延生成するためです。

現在の制限点
キャプチャグループ、遅延量化子 (

.*?
)、ストリーミング API には対応しておらず、マッチ境界のみが返されます。

今後の展開と影響
計画中の拡張としては、キャプチャグループや遅延量化子、ストリーミングインターフェースへのサポートがあります。RE# はすでに grep スタイルの「re」ツールで使用されており、一回パスで多項語ブール検索を実行しています。RE# を採用することで、開発者はサービス拒否リスクを避けつつ POSIX の意味論を維持し、信頼できない入力に対して線形時間の性能を達成できます。

本文

検索性能と二次的爆発

あるパターンを文書内で探すのに1秒かかる場合、同じ検索を100倍大きいテキストで繰り返すとほぼ3時間まで拡大します。RE2、Go の

regexp
、Rust の
regex
クレート、.NET の NonBacktracking モードなど、どの正規表現エンジンも「単一一致に対しては線形時間でマッチできる」と主張しています。しかし、
find_iter
(または
FindAll
)といったイテレーターを呼び出すと、その保証は消えてしまいます。Rust の正規表現ドキュメントだけが明確に次のように述べています。

「イテレーターの最悪ケース時間計算量は O(m × n²) です … パターンもヒストックも信頼できない場合、すべての一致を列挙するときには二次的な時間計算量に陥ります。これを回避する方法はありません。」

典型例として

.*a|b
というパターンと n 個の
b
だけで構成された文字列があります。各位置でエンジンはまず
.*a
を試し、残りのヒストックをスキャンして
a
を探します(失敗)。次に
b
ブランチがマッチし、一文字進み再び同じことを繰り返します。計算量は
( n + (n-1) + (n-2) + \dots = O(n²))。

Russ Cox は 2009 年にこれを指摘しており、BurntSushi の rebar ベンチマークは RE2、Go、Rust 全てで入力が倍増するとスループットが半減することを確認しています。


なぜ長い間見逃されていたのか?

多くの学術的正規表現論文は「単一一致問題」に焦点を当てています。理論ではすべてを「マッチする/しない」という yes/no の質問に還元します。これでは一致がどこで起きるか、何個あるか、その長さは無視されます。「マッチするかしない」だけを考えると、全一致問題は見えなくなります。

バックトラッキングエンジンはさらに悪いです:ユーザーが入力したパターンと 50 文字の入力で、宇宙の熱的死よりも長くかかる指数時間に陥ることがあります。Thompson の NFA 構築(1968)はこれを回避しましたが、バックトラッキングは多くのエンジンでデフォルトです。私の GitHub セキュリティアラート(2026 年 3 月)では、npm の glob マッチャー

minimatch
が 5 件の ReDoS CVE に遭遇し、すべてバックトラッキングによるものであることが分かります。

二次的全一致問題はより微妙で、バックトラッキングを避けるように設計されたエンジンにも影響します。ブラウザをクラッシュさせるほどではありませんが、1 秒の検索を 3 時間に変える可能性があります。


歴史的解決策

Aho–Corasick(1975)

固定文字列 のみの場合、Aho–Corasick アルゴリズムは O(n) ですべての出現を見つけます。トライに失敗リンクを構築し、マッチすると正確に終点が分かるため再スキャンが不要です。ただし文字列がリテラルのみの場合に限ります。

Hyperscan / Vectorscan

これらのエンジンは earliest‑match(最初にマッチ状態に入った瞬間を報告)というセマンティクスを採用します。ネットワーク侵入検知では問題ありませんが、

grep
のようなツールでは結果が変わります。例:
a+
aaaa
に適用すると、一つの長いマッチではなく四つの一文字マッチが報告されます。

REmatch(VLDB 2023)

すべての有効

(start, end)
スパンを列挙します。重複や入れ子も含めて、
a+
aaaa
に適用すると 10 個のスパンが出力されます。そのため出力自体が O(n²) になることがあります。


RE# – 二段階線形時間全一致

RE# はパターンや入力に関係なく、すべてのマッチを二つのパスで見つける最初の正規表現エンジンです。セマンティクスは変更しません。

  1. 逆 DFA がマッチ開始位置となり得る場所をマークします。
  2. 順 DFA が各マークされた位置で最長マッチを解決します。

マッチは再起動せずに後から報告されます。アルゴリズムは任意のパターンに対して機能し、文字列がリテラルのみという制限はありません。


ハードナードモード

二段階で再起動コストを排除したものの、順方向パスではまだ一度に一つのマッチしか解決できません。曖昧な境界を持つ悪質なパターン(例:

.*a|b
)はこのパス内でも二次的作業を発生させます。

ハードナードモード は順方向パスを O(n × S) の走査に置き換えます (

S
= 同時にアクティブな DFA 状態数)。これで一度のパスで すべて のマッチ終点を解決し、左側最長(POSIX)セマンティクスを保ちつつ意味的トレードオフはありません。

入力サイズ通常速度ハードナード速度
1 0000.7 ms25× (≈28 µs)
5 00018 ms123× (≈146 µs)
10 00073 ms241× (≈303 µs)
50 0001.8 s1.6 ms

通常モードは二次的ですが、ハードナードは線形を保ちます。


ハードナードモードの使用タイミング

  • 不正、ユーザー提供パターン:攻撃者が悪質なケースを作成できる場合。
  • セキュリティクリティカル環境(例:Web サービス、ログパーサ)。
let re = Regex::with_options(
    pattern,
    EngineOptions::default().hardened(true)
)?;

通常テキストでは、二次的ケースを引き起こす可能性のあるパターンに対して 3〜20 倍程度の遅延が生じます。実際には

[A-Z][a-z]+
のような境界が明確な正規表現はほとんどで、ハードナードモードを有効にしても影響はありません。


Aho–Corasick との比較

RE# のハードナードモードは、マッチ長が事前に分からない完全正規表現へ Aho–Corasick を拡張したものです。逆パスで確認済みの開始位置だけに新しい候補を追加し、アクティブなマッチ候補セットを保持して各文字で全候補を導関数(derivative)で進めます。

ベンチマーク(2 663 語の辞書 vs 約 900 KB のプローズ):

エンジンスループット
Rust
regex
627 MiB/s
Aho–Corasick163 MiB/s (≈3.85× 遅い)
RE# 通常535 MiB/s (≈1.17×速い)
RE# ハードナード155 MiB/s (≈4.05×遅い)

RE# は派生ベースの DFA が小さく、キャッシュ効率が高いため、二段階であっても高速です。


スキップアクセラレーション & リテラル重視パターン

RE# には AVX2/NEON 用の手書き実装があります:

  • レアバイト検索
  • テディマルチポジションマッチング
  • 文字クラススキャン(範囲ベース)

これにより、リテラル重視のベンチマーク(rebar スイート)で

regex
とほぼ同等に近づきます。


ストリーミングとその他制限

機能状態
ストリーミングインタフェース未実装
find_all
はスライスを受け取ります。チャンクストリームは計画中です。
キャプチャグループなし。RE# は境界のみ返します。キャプチャは別エンジンで後処理できます。
ラジー量化子(
.*?
不可。RE# は左側最長(POSIX)セマンティクスを採用しており、ラジー量化子はバックトラッキング概念に依存します。

実践例:
re
grep ツール

RE# は多項語 Boolean 検索とスコーピングをサポートする簡易 grep ライクなユーティリティです。

# "unsafe" と "unwrap" の両方が含まれる行を検索
re --near 5 -a unsafe -a unwrap src/

# "serde" と "async" 両方を含むファイル一覧
re --scope file -a serde -a async src/

RE# パターンを直接使用することも可能です。


今後の展望

RE# はまだ開発中で、正式な 1.0 リリースは未定ですが進捗は続いています。PLDI に条件付きで受理された論文があります。今後はキャプチャグループ対応とハードナードモードを lookaround 向けに改善する予定です。

同じ日のほかのニュース

一覧に戻る →

2026/03/24 7:52

Windows 3.1 用 タイル背景 .bmp アーカイブ

## Japanese Translation: GitHubは、コード作成・ワークフロー自動化・セキュリティ・コミュニティ協働を向上させるAI搭載の開発者ツールとエンタープライズサービスの包括的なスイートを提供します。 - **AI コード生成**:Copilot、Spark、および Models は開発者がコードを自動で生成・改善するのに役立ちます。 - **開発者ワークフロー**:Actions、Codespaces、Issues、Plan、Code Review が、コーディングからデプロイまでの開発パイプライン全体を統括します。 - **セキュリティ**:GitHub Advanced Security は脆弱性を検出しシークレットを保護します;エンタープライズグレードのセキュリティは Copilot for Business にバンドルされています。 - **エンタープライズプラットフォーム**:AI 搭載の開発環境とプレミアムサポートにより、大規模チームがスケールで高度なツールを採用できるようになります。 - **ユースケースの幅広さ**:このスタックは、医療・金融・製造・政府などの業界で App Modernization、DevSecOps、および CI/CD をサポートします。 - **マーケットプレイスとコミュニティ**:Advanced Security のようなアドオンは Marketplace で入手可能です;Sponsors、Security Lab、Maintainer Community、Accelerator、Stars、Archive Program といったイニシアチブがオープンコラボレーションを促進します。 - **ドキュメントとサポート**:GitHub は包括的なドキュメント、ブログ、変更ログ、およびユーザー向け専用サポートチャネルを提供しています。 今後の展望として、GitHub は AI 統合を深化させ、エンタープライズ機能を拡充し、業界固有のサポートを拡大することを計画しており、デジタルトランスフォーメーションの加速、コード品質基準の向上、および組織全体でのセキュリティ強化に寄与すると期待されています。

2026/03/24 3:40

既存の研究アイデアに対する自己主導型調査

## Japanese Translation: 研究は、検索空間とサンドボックス制約が厳密に定義された場合、LLM駆動エージェントが機械学習トレーニングパイプラインを自律的に改善できることを示しています。エージェントは制限付きループで動作します:仮説 → `train.py`/`program.md` を編集(メモリ用にスクラッチパッド使用)→ トレーニング(RTX 4090 で約800ステップ ≈ 3 分)→ 平均順位を評価し、コミットまたはロールバック。各実行はノイズ過剰適合を防ぐために約5 分の壁時計時間で制限されます。 トレーニングは医療用X線データセットから始まり、その後 Ukiyo‑eVG(≈11 K 日本の木版画)へ切り替えました。フレーズ注釈はガウスヒートマップに変換され、追加の「視線」入力として使用されました。CLIPバックボーンは ViT‑Small (22 M) + DistilBERT (66 M) + HeatmapProcessor (~90 M パラメータ) で構成され、ホールドアウト1 Kテストセットで評価しました(ベースライン平均順位 344.68、R@1 img→txt 17.2%、txt→img 16.5%)。 1日間にわたりエージェントは42実験を実行し、そのうち13がコミットされ29がロールバックされました。平均順位は344.68から157.43へ(54 %減少)しました。主な向上は温度制限修正(-113点)と Optuna++ ハイパーパラメータ調整(-30点)によるもので、他のアーキテクチャ変更はほぼ影響がありませんでした。フェーズ 4/5では成功率が低下し、多くの「スパゲッティ」仮説が失敗しました;サンドボックス違反は、エージェントが未承認の bash 呼び出しを試みたりループを早期に停止した際に発生しました。 実験は、LLM エージェントが明確に定義された検索空間内で機械学習研究を自律的に推進できることを示していますが、予期せぬ(「未知の未知」)挙動には苦戦し、厳格なサンドボックス化が必要です。将来の作業では計画段階やサブエージェントを導入して、1実験あたりの単一変更制限を克服し、ハイパーパラメータのより深い探索と成功率の向上を可能にすることが考えられます。

2026/03/22 0:07

**朱祁:磁器修復の技術**

## Japanese Translation: **概要:** ジュチ(锔瓷)は、宋代(960‑1279)に遡る中国の破損した磁器を修復する工芸です。13世紀の絵画に作業員が壊れた陶器を修理している様子が描かれており、ユネスコはジュチを無形文化遺産として認定しています。この技術では、職人が**脆弱な磁器に穴を開け、慎重に手作業で製造した金属のスタープレート(銅、鉄、または貴金属)を挿入し、裂け目を覆いながら物体の機能と美的整合性を保ちます**。ジュチは「不完全さの美」を称える哲学を具現化しており、日本の金継ぎ(壊れた陶器を漆で修復し、金箔で縫い合わせる)と類似しています。両方の伝統において、裂け目は再生されたアイデンティティへ変容し、人生に伴う傷や回復力を象徴します

正規表現で全てのマッチを探すことは、常に O(n²) でした。 | そっか~ニュース