データ検証や文字列の抽出・加工で「LIKE演算子では対応できない複雑なパターンを扱いたい」という場面があります。そんなときに役立つのがOracleのREGEXP関数群です。Oracle 10g以降に導入されたこれらの関数はPOSIX準拠の正規表現をSQLから直接使えるようにしたもので、データクレンジング・バリデーション・ログ解析など幅広い用途に対応します。本記事では5つのREGEXP関数を構文・オプション・実務パターンまで体系的に解説します。
- OracleのREGEXP関数5種の構文と使い分け
- POSIX正規表現のメタ文字・文字クラス一覧
- 大文字小文字を区別しないなど修飾子(マッチパラメータ)の使い方
- REGEXP_LIKEによるWHERE条件での絞り込み
- REGEXP_REPLACEによる文字列の置換・除去
- REGEXP_SUBSTRによるパターンに一致した部分文字列の抽出
- REGEXP_INSTR / REGEXP_COUNTの活用
- メールアドレス検証・電話番号抽出・HTMLタグ除去など実務パターン
OracleのREGEXP関数とは
Oracleは10g(10.1.0)以降、POSIX 1003.2準拠の正規表現をサポートするREGEXP関数群を提供しています。通常の LIKE 演算子では %(0文字以上の任意文字列)と _(任意の1文字)しか使えませんが、正規表現ではより細かいパターンを表現できます。
| 関数名 | 役割 | 戻り値 |
|---|---|---|
| REGEXP_LIKE | 文字列が正規表現にマッチするか判定 | TRUE / FALSE(WHERE・CHECK制約で使用) |
| REGEXP_REPLACE | マッチした部分を別の文字列に置換 | 置換後の文字列(VARCHAR2) |
| REGEXP_SUBSTR | マッチした部分文字列を抽出 | マッチした文字列(VARCHAR2) |
| REGEXP_INSTR | マッチした部分の開始位置を取得 | 位置(NUMBER) |
| REGEXP_COUNT | マッチした回数を取得 | 件数(NUMBER) |
正規表現のメタ文字一覧
OracleのREGEXP関数で使える主なメタ文字です。
| メタ文字 | 意味 | 例 |
|---|---|---|
. |
任意の1文字(改行を除く) | a.c → abc, aXc |
* |
直前の要素の0回以上の繰り返し | ab* → a, ab, abb |
+ |
直前の要素の1回以上の繰り返し | ab+ → ab, abb |
? |
直前の要素の0回または1回 | colou?r → color, colour |
{n} |
直前の要素のちょうどn回 | [0-9]{4} → 4桁の数字 |
{n,m} |
直前の要素のn〜m回 | [0-9]{2,4} → 2〜4桁 |
^ |
文字列の先頭 | ^ABC → ABCで始まる |
$ |
文字列の末尾 | xyz$ → xyzで終わる |
[...] |
文字クラス(いずれか1文字) | [aeiou] → 母音1文字 |
[^...] |
否定文字クラス(含まれない1文字) | [^0-9] → 数字以外 |
| |
OR(いずれかのパターン) | cat|dog → cat または dog |
() |
グループ化・キャプチャ | (ab)+ → ab, abab |
\d |
数字([0-9]と同等) | \d{3} → 3桁の数字 |
\w |
英数字とアンダースコア | \w+ → 1文字以上の単語 |
\s |
空白文字(スペース・タブ・改行) | \s+ → 1つ以上の空白 |
POSIXブラケット式(文字クラス)
Oracleの正規表現では [:class:] 形式のPOSIXブラケット式も使えます。マルチバイト文字(日本語など)を含む場合はこちらが安全です。
| 記法 | 意味 |
|---|---|
[:alpha:] |
アルファベット(A-Z, a-z) |
[:digit:] |
数字(0-9) |
[:alnum:] |
英数字([:alpha:]+[:digit:]) |
[:upper:] |
大文字(A-Z) |
[:lower:] |
小文字(a-z) |
[:space:] |
空白文字 |
[:punct:] |
句読点・記号 |
マッチパラメータ(修飾子)
各REGEXP関数の末尾に指定できるマッチパラメータで、パターンマッチの挙動を変えられます。
| パラメータ | 意味 |
|---|---|
i |
大文字小文字を区別しない(case-insensitive) |
c |
大文字小文字を区別する(case-sensitive、デフォルト) |
m |
複数行モード。^$が各行の先頭・末尾にマッチ |
n |
.が改行文字にもマッチする |
x |
空白とコメント(#以降)を無視(拡張モード) |
REGEXP_LIKE
WHERE句やCHECK制約で使うパターンマッチ関数です。戻り値はTRUE/FALSEのため、SELECT の戻り値として使えず、条件式でのみ利用します。
構文:REGEXP_LIKE(source_char, pattern [, match_param])
-- 数字のみで構成される行を抽出 SELECT employee_id, phone_number FROM employees WHERE REGEXP_LIKE(phone_number, '^[0-9]+$'); -- アルファベットで始まる名前(大文字小文字不問) SELECT first_name FROM employees WHERE REGEXP_LIKE(first_name, '^[a-z]', 'i'); -- 'i' = 大文字小文字を区別しない -- ひらがな・カタカナを含む行を除外 SELECT customer_name FROM customers WHERE NOT REGEXP_LIKE(customer_name, '[[:alpha:]]');
-- メールアドレス形式のCHECK制約
ALTER TABLE users
ADD CONSTRAINT chk_email_format
CHECK (REGEXP_LIKE(email, '^[A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,}$'));
-- 郵便番号(7桁数字またはハイフンあり形式)のCHECK制約
ALTER TABLE addresses
ADD CONSTRAINT chk_zip_format
CHECK (REGEXP_LIKE(zip_code, '^[0-9]{3}-?[0-9]{4}$'));
REGEXP_REPLACE
パターンにマッチした部分を別の文字列に置換します。第3引数で空文字列を指定すれば、マッチした部分を削除できます。
構文:REGEXP_REPLACE(source_char, pattern [, replace_string [, position [, occurrence [, match_param]]]])
| 引数 | 説明 | デフォルト |
|---|---|---|
| source_char | 検索対象の文字列 | ― |
| pattern | 正規表現パターン | ― |
| replace_string | 置換後の文字列(省略時はNULL) | NULL |
| position | 検索開始位置(1始まり) | 1 |
| occurrence | 何番目のマッチを置換するか(0=全て) | 0 |
| match_param | 修飾子(i, c, m, n, x) | なし |
-- 数字以外の文字を全て除去(電話番号のハイフン・括弧を取り除く)
SELECT
phone_raw,
REGEXP_REPLACE(phone_raw, '[^0-9]', '') AS phone_digits_only
FROM (
SELECT '090-1234-5678' AS phone_raw FROM dual UNION ALL
SELECT '(03)1234-5678' FROM dual UNION ALL
SELECT '0312345678' FROM dual
);
-- 結果: 09012345678 / 0312345678 / 0312345678
-- 連続する空白を1つにまとめる
SELECT REGEXP_REPLACE('Hello World !', '\s+', ' ') AS normalized
FROM dual;
-- 結果: 'Hello World !'
-- HTMLタグを除去する
SELECT REGEXP_REPLACE(
'太郎さんへ',
'<[^>]+>', -- < から始まり > で終わるHTMLタグにマッチ
'' -- 空文字で置換(削除)
) AS plain_text
FROM dual;
-- 結果: '太郎さんへ'
-- 先頭・末尾の空白を削除(TRIMと同等だが正規表現版)
SELECT REGEXP_REPLACE(' hello world ', '^\s+|\s+$', '') AS trimmed
FROM dual;
-- 結果: 'hello world'
-- 後方参照を使って日付形式を変換(YYYYMMDD → YYYY/MM/DD)
SELECT
REGEXP_REPLACE('20260328', '^([0-9]{4})([0-9]{2})([0-9]{2})$', '//')
AS formatted_date
FROM dual;
-- 結果: '2026/03/28'
-- 氏名の「姓名」順を「名姓」に入れ替え
SELECT
REGEXP_REPLACE('Yamada Taro', '^(\S+)\s+(\S+)$', ' ') AS swapped
FROM dual;
-- 結果: 'Taro Yamada'
後方参照(バックリファレンス)では 〜\9 でキャプチャグループを参照します。これは通常の REPLACE 関数にはない強力な機能です。改行コードの置換については【Oracle】改行コードを置換・削除する方法完全ガイドも参照してください。
REGEXP_SUBSTR
パターンにマッチした部分文字列を返します。マッチしない場合は NULL を返します。
構文:REGEXP_SUBSTR(source_char, pattern [, position [, occurrence [, match_param [, subexpr]]]])
| 引数 | 説明 | デフォルト |
|---|---|---|
| position | 検索開始位置(1始まり) | 1 |
| occurrence | 何番目のマッチを返すか | 1 |
| match_param | 修飾子 | なし |
| subexpr | 返すキャプチャグループの番号(0=マッチ全体) | 0 |
-- 文字列から最初の数値を抽出
SELECT
REGEXP_SUBSTR('Order #12345 shipped', '[0-9]+') AS order_num
FROM dual;
-- 結果: '12345'
-- 2番目のマッチを取得(occurrence=2)
SELECT
REGEXP_SUBSTR('abc123def456ghi', '[0-9]+', 1, 2) AS second_num
FROM dual;
-- 結果: '456'
-- ドメイン名だけを抽出(@以降の部分)
SELECT
REGEXP_SUBSTR(email, '@(.+)$', 1, 1, 'i', 1) AS domain
FROM users;
-- subexpr=1 で1番目のキャプチャグループを返す
-- CSV形式の文字列から各要素を取り出す(occurrence を変えながらSELECT)
SELECT
REGEXP_SUBSTR('apple,banana,cherry,date', '[^,]+', 1, 1) AS item1,
REGEXP_SUBSTR('apple,banana,cherry,date', '[^,]+', 1, 2) AS item2,
REGEXP_SUBSTR('apple,banana,cherry,date', '[^,]+', 1, 3) AS item3,
REGEXP_SUBSTR('apple,banana,cherry,date', '[^,]+', 1, 4) AS item4
FROM dual;
-- 結果: apple / banana / cherry / date
SELECT
email,
REGEXP_SUBSTR(email, '^[^@]+') AS local_part, -- @より前
REGEXP_SUBSTR(email, '[^@]+$') AS domain_part -- @より後
FROM users
WHERE REGEXP_LIKE(email, '^[^@]+@[^@]+\.[^@]+$'); -- 有効なメール形式のみ
REGEXP_INSTR
パターンにマッチした部分の開始位置(または終了位置の次)を返します。マッチしない場合は0を返します。
構文:REGEXP_INSTR(source_char, pattern [, position [, occurrence [, return_opt [, match_param [, subexpr]]]]])
return_opt に 0 を指定するとマッチ開始位置、1 を指定するとマッチ終了位置の次を返します。
-- 最初の数字の開始位置を取得
SELECT
REGEXP_INSTR('Price: 1980 yen', '[0-9]+') AS pos
FROM dual;
-- 結果: 8 ('1'の位置)
-- マッチ終了の次の位置を取得(return_opt=1)
SELECT
REGEXP_INSTR('Price: 1980 yen', '[0-9]+', 1, 1, 1) AS pos_after
FROM dual;
-- 結果: 12 ('0'の次)
-- IPアドレスの第2オクテットの開始位置
SELECT
REGEXP_INSTR('192.168.0.1', '[0-9]+', 1, 2) AS second_octet_pos
FROM dual;
-- 結果: 5 ('168'の開始位置)
-- 特定パターンが存在するかどうかの確認(0 = 存在しない)
SELECT
CASE
WHEN REGEXP_INSTR(description, '<script', 1, 1, 0, 'i') > 0
THEN 'XSS疑い'
ELSE 'OK'
END AS security_check
FROM articles;
REGEXP_COUNT
パターンがマッチした回数を返します。Oracle 11g Release 1以降で使用可能です。
構文:REGEXP_COUNT(source_char, pattern [, position [, match_param]])
-- 文字列中の数字の塊の数を数える
SELECT
REGEXP_COUNT('abc123def456ghi789', '[0-9]+') AS num_groups
FROM dual;
-- 結果: 3
-- カンマの数(要素数 - 1)を数える
SELECT
product_code,
REGEXP_COUNT(tags, ',') + 1 AS tag_count
FROM products;
-- 特定の単語が何回登場するか
SELECT
REGEXP_COUNT(description, 'Oracle', 1, 'i') AS oracle_mentions
FROM articles;
-- は単語境界(単語の境界を示すアサーション)
REGEXP_LIKEとREGEXP_REPLACE・REGEXP_SUBSTR・REGEXP_INSTRは Oracle 10g(10.1.0)から使えますが、REGEXP_COUNTは Oracle 11g Release 1(11.1.0)以降で追加されました。古い環境では使用できないため、バージョンに応じて代替手段(LENGTH(REGEXP_REPLACE(src, pattern, ”))で文字を消した長さの差分など)を使います。
実務でよく使うパターン
メールアドレスの形式チェックと抽出
-- 正規表現によるメールアドレスバリデーション
SELECT
email,
CASE
WHEN REGEXP_LIKE(email,
'^[A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,}$')
THEN '有効'
ELSE '無効'
END AS email_status
FROM users;
-- ドメインだけを一覧で集計
SELECT
REGEXP_SUBSTR(email, '@(.+)$', 1, 1, NULL, 1) AS domain,
COUNT(*) AS user_count
FROM users
WHERE REGEXP_LIKE(email, '@')
GROUP BY REGEXP_SUBSTR(email, '@(.+)$', 1, 1, NULL, 1)
ORDER BY user_count DESC;
電話番号の正規化
-- 様々な形式の電話番号を数字のみにする
SELECT
phone_raw,
REGEXP_REPLACE(phone_raw, '[^0-9]', '') AS digits_only
FROM (
SELECT '090-1234-5678' AS phone_raw FROM dual UNION ALL
SELECT '(090)1234 5678' FROM dual UNION ALL
SELECT '090.1234.5678' FROM dual UNION ALL
SELECT '09012345678' FROM dual
);
-- ハイフン区切り形式に統一(11桁の携帯番号)
SELECT
REGEXP_REPLACE(
REGEXP_REPLACE(phone_raw, '[^0-9]', ''), -- まず数字だけにする
'^([0-9]{3})([0-9]{4})([0-9]{4})$', -- 3-4-4 に分割
'--'
) AS formatted_phone
FROM customers;
郵便番号の検証
-- 〒123-4567 / 1234567 どちらも許可するバリデーション
SELECT
zip_code,
CASE
WHEN REGEXP_LIKE(zip_code, '^[0-9]{3}-?[0-9]{4}$')
THEN '正常'
ELSE '不正'
END AS zip_status
FROM addresses;
-- ハイフンなしに統一する
SELECT
REGEXP_REPLACE(zip_code, '-', '') AS zip_normalized
FROM addresses
WHERE REGEXP_LIKE(zip_code, '^[0-9]{3}-?[0-9]{4}$');
HTMLタグ・制御文字の除去
-- HTMLタグを全て除去してプレーンテキストに変換
SELECT
REGEXP_REPLACE(html_content, '<[^>]+>', '') AS plain_text
FROM articles;
-- 制御文字(タブ・改行・復帰)を除去
SELECT
REGEXP_REPLACE(raw_text, '[[:cntrl:]]', '') AS clean_text
FROM import_data;
-- 英数字・スペース以外の文字を除去(記号をすべて削除)
SELECT
REGEXP_REPLACE(user_input, '[^[:alnum:] ]', '') AS safe_text
FROM user_comments;
ログ解析・文字列の分解
-- アクセスログ例: "192.168.1.100 - [28/Mar/2026:10:30:00] GET /index.html 200"
SELECT
log_line,
REGEXP_SUBSTR(log_line, '^[0-9.]+') AS ip_address,
REGEXP_SUBSTR(log_line, '\[([^\]]+)\]', 1, 1, NULL, 1) AS access_time,
REGEXP_SUBSTR(log_line, '(GET|POST|PUT|DELETE) \S+', 1, 1) AS method_path,
REGEXP_SUBSTR(log_line, ' ([0-9]{3})$', 1, 1, NULL, 1) AS status_code
FROM access_logs;
LIKE vs REGEXP_LIKE の使い分け
| 比較項目 | LIKE | REGEXP_LIKE |
|---|---|---|
| パターンの柔軟性 | % と _ のみ | POSIX正規表現フル対応 |
| パフォーマンス | インデックスを活用しやすい | 全件スキャンになりやすい |
| 可読性 | シンプル | 複雑なパターンを簡潔に書ける |
| 推奨ケース | 前方一致・後方一致など単純なパターン | 文字クラス・繰り返し・選択など複雑なパターン |
REGEXP関数はWHERE句に使うとインデックスが効かず全件スキャンになる場合がほとんどです。大量データへの適用は夜間バッチやデータクレンジング用途に限定し、頻繁に参照されるオンラインクエリへの無制限な適用は避けてください。文字列操作関数の詳細は【Oracle】SUBSTR()関数で文字列の一部を切り出す方法や【Oracle】文字列の文字数・バイト数を取得する方法も参考にしてください。
まとめ
OracleのREGEXP関数群は5種類あり、それぞれ役割が異なります。
- REGEXP_LIKE:WHERE句・CHECK制約でパターンマッチ判定。入力バリデーションに最適
- REGEXP_REPLACE:マッチした文字列を置換・削除。後方参照でフォーマット変換も可能
- REGEXP_SUBSTR:マッチした部分を抽出。
subexpr引数でキャプチャグループも取れる - REGEXP_INSTR:マッチした位置番号を返す。存在チェックや部分文字列のオフセット計算に使う
- REGEXP_COUNT:出現回数を返す(11g R1以降)。パターンの頻度分析に便利
- パフォーマンス:WHERE句での使用はインデックスが使われないため、大量データへの適用は慎重に
LIKE演算子で対応できない複雑なパターン検証・データクレンジングにはREGEXP関数を積極的に活用し、シンプルな前方一致・後方一致はLIKEを使うという使い分けが実務での鉄則です。DECODE関数など他の文字列操作との組み合わせ方は【Oracle】条件に合致する場合に別の値を返すDECODE関数の使い方も参照してください。

