DevToolBox

正規表現で「〜以外」を書く方法 - 否定先読み・文字クラス除外

最終更新日: 2026-07-22公開日: 2026-07-22執筆: DevToolBox編集部

「正規表現で特定の文字以外にマッチしたい」「ある文字列を含まない行だけを探したい」場合、 対象が1文字文字列かで書き方が変わります。 正規表現の否定には、否定文字クラス・否定先読み・否定後読みを使い分けます。 このページの例はRegex Testerで実際に試せます。

Regex has different ways to express "not" depending on whether you need to exclude one character or reject a whole string. Use a negated character class, negative lookahead, or negative lookbehind according to which position and text you need to test.

1. 1文字だけ除外する: 否定文字クラス [^abc]

/[^abc]/g

文字クラスの先頭に ^ を置くと、その集合に含まれない1文字に マッチします。[^abc] は「a、b、c以外の1文字」という意味です。abcXYZ なら、XYZ がそれぞれマッチします。 正規表現で特定の文字以外を探すときの基本形です。

// 数字以外の1文字
/[^0-9]/g

// スラッシュ以外が1文字以上続く部分
/[^/]+/g

2. ドット . と否定文字クラスの違い

/.       // 通常は改行以外の任意の1文字
/[^abc]  // a、b、c以外の任意の1文字

ドット . は通常、改行以外の任意の1文字にマッチします。一方、[^abc] は改行を含めて「指定した文字以外」を表します。 JavaScriptでは s(dotAll)フラグ付きのドットは改行にもマッチします。 「何でもよい」ならドット、「この文字だけ除く」なら否定文字クラスです。

3. 特定の文字列を含まない: 否定先読み (?!pattern)

/^(?!.*foo).*$/gm

このパターンは foo を含まない行だけにマッチします。行頭 ^ で 否定先読み (?!.*foo) を評価し、行内に foo がないことを確認してから、.*$ で行全体を取得します。大文字・小文字を同一視するなら iフラグを追加します。正規表現で特定の文字列を含まない条件や、検索結果から文字列を除く 条件には、文字クラスではなく否定先読みが適しています。

// .tmp で終わらないファイル名
/^(?!.*\.tmp$).+$/

// error を含まない行(大文字・小文字を無視)
/^(?!.*error).*$/gim

4. 特定の文字列の後ろに続かない: 否定後読み (?<!pattern)

/(?<!USD)(?<!\d)\d+/g

否定後読み (?<!USD) は、現在位置の直前が USD ではない場合だけ マッチを許可します。ただし\b(単語境界)は英字と数字を区別しないため、USD100のように英字と数字が地続きの場合はD1の間に 境界が生まれず、\b\d+\bでは数字に一致できません。数字の先頭であることを保証するには(?<!\d)(直前が数字でない)を追加します。この形ならUSD100 JPY200USD の直後の 100 を除き、200 にだけマッチします。 「直後に特定の文字列がない」を見る否定先読みとは、見る方向が逆です。

5. 否定先読み・否定後読みのブラウザ対応

否定先読みは主要ブラウザで長く対応されています。否定後読みは比較的新しく、 Safariでは16.4以降で対応しました。古いブラウザでは、キャプチャやJavaScript側の 条件判定に置き換える選択肢もあります。詳しくは正規表現の後読みとブラウザ対応を参照してください。

複数行テキストでの否定:mフラグの有無で挙動が変わる

/^(?!.*foo).*$/ を複数行のテキストに使う場合、m(multiline)フラグを 忘れると意図通りに動きませんmフラグが無いと ^ は文字列全体の先頭、$ は文字列全体の末尾にしかマッチせず、1行ずつの判定になりません。

const text = "line1 ok\nline2 has foo\nline3 ok";

// ❌ mフラグなし: ^と$が文字列全体の先頭・末尾を指すため、1行目しか判定されない
text.match(/^(?!.*foo).*$/g);

// ✅ mフラグあり: ^と$が各行の先頭・末尾を指し、行ごとに判定される
text.match(/^(?!.*foo).*$/gm); // ["line1 ok", "line3 ok"]

逆に、改行を含む文字列全体を1つのかたまりとして「どこにもfooが無いこと」を確認したい場合は、mフラグではなくs(dotAll)フラグや[\s\S]*を使い、.が改行もまたぐようにします。「行ごとの判定」か「全体の判定」かで、 必要なフラグが変わる点を混同しないようにしてください。

実務でよく使う否定パターン集

やりたいこと / Goalパターン
.tmp / .log 以外のファイル名/^(?!.*\.(tmp|log)$).+$/
#で始まるコメント行を除外/^(?!\s*#).+$/gm
HTMLタグを含まない行/^(?!.*<[^>]+>).*$/gm
example.comドメイン以外のURL/https?:\/\/(?!example\.com)\S+/g

いずれも「1文字の除外」ではなく「文字列・行単位の除外」なので、[^...]ではなく 否定先読みを使う場面です。実際のデータで試す際はRegex Testerで テスト文字列を差し替えながら確認してください。

よくある間違い

Regex Testerで試す

Regex Testerにパターンとテスト文字列を貼り付けると、 マッチ箇所をすぐ確認できます。否定先読みの位置や mis フラグを切り替え、期待する行だけが残るか比較してみてください。

English summary

Use [^abc] to match one character other than a, b, orc; it does not exclude the string abc. To match a line that does not contain foo, use ^(?!.*foo).*$. Negative lookahead(?!pattern) checks what does not follow the current position, while negative lookbehind (?<!pattern) checks what does not precede it. Both are zero-width assertions. Lookbehind is newer and requires Safari 16.4 or later.

関連ツール / Related tools

関連ガイド / Related guides