Oracle

文字列前後の空白をすべて除去する正規表現【Oracle SQL】

記事内に商品プロモーションを含む場合があります

こんにちは、すみです。

当記事は、こんな内容になっております。

  • 正規表現を使って文字列前後にある空白を削除してOracle DBからデータを取得したい
  • 空白は半角スペースと全角スペースの両方に対応
  • 削除するのは文字列前後のみで、文字間の空白は削除せずに残す

文字列前後の空白を除去できる正規表現【結論】

下記の正規表現を用いて、文字列前後の空白を除去した値を取得できます。

SELECT REGEXP_REPLACE(対象文字列, ‘^[  ]+|[  ]+$’, )
FROM dual;

たとえば、対象文字列を

(全角スペース)(半角スペース)あいう(全角スペース)えお(全角スペース)(半角スペース)

とした場合、

SELECT REGEXP_REPLACE(‘  あいう えお  ‘, ‘^[  ]+|[  ]+$’, )
FROM dual;

この実行結果は

あいう(全角スペース)えお

となり、文字列前後の空白が空文字に置き換えられ(=空白が除去され)、文字間の空白は残ったままになります。

REGEXP_REPLACE関数について

Oracleで用意されているREGEXP_REPLACE関数は、次のように使用することで任意の文字または文字列を別の文字に置き換えることができます。

REGEXP_REPLACE(対象文字列, 正規表現, 置き換えたい文字)

たとえば、

REGEXP_REPLACE(’ABC’, 「文字列末尾がCなら」という意味の正規表現, ’D’)

として実行した場合、実行結果は「ABD」となります。

正規表現の解説

正規表現を分解して、それぞれの意味を整理しました。

文字列先頭の空白を除去【^[  ]+】

「^」は文字列の先頭を表します。

「[]」は、その中に含まれた任意の1文字を表します。ブログだとわかりにくいですが、今回の[]には、半角スペースと全角スペースが1文字ずつ入っています。

「+」は、直前の文字や文字列が1回以上繰り返されることを意味します。[]に含まれた単体の文字だけではなく、文字列としての判定も可能になります。

たとえば、

  • 半角スペース1つ
  • 半角スペース2つ
  • 半角スペース1つと全角スペース1つ
  • 全角スペース2つと半角スペース1つと全角スペース1つ

などなど。

半角スペース、全角スペースそれぞれ単体だけではなく、それを組み合わせた文字列についても、すべて対象とすることができます。

これらを組み合わせた「^[  ]+」は、文字列の先頭にある1つ以上の半角スペースまたは全角スペース(組み合わせ含む)を表現しています。

文字列末尾の空白を除去【[  ]+$】

「[]」と「+」については、先ほど記載した文字列先頭のときと同じ意味になります。つまり「[]に含まれる1つ以上の文字または文字列を表す」ということですね。

先ほどと異なるのは、先頭にあった「^」がなくなり、末尾に「$」がついていることです。この「$」は、文字列の末尾を表します。

以上から、「[  ]+$」は文字列の末尾にある1つ以上の半角スペースまたは全角スペース(組み合わせ含む)を表現していることがわかりました。

ORを意味する【|】

今回の正規表現

REGEXP_REPLACE(対象文字列, ‘^[  ]+|[  ]+$’, )

REGEXP_REPLACE() は3つの引数を持っています。

  • 第一引数:対象となる文字列
  • 第二引数:正規表現
  • 第三引数:置き換えたい文字

正規表現の中に、先ほど解説した「^[  ]+」と「[  ]+$」以外にもう1つ、文字がありますね。「|」です。

「|」は、日本語にすると「〇または〇なら」という意味になります。IF文のORと一緒ですね。

つまりこちらの正規表現は、

文字列の先頭に半角スペース、全角スペース(その組み合わせ)を含む

または

文字列の末尾に半角スペース、全角スペース(その組み合わせ)を含む

なら

という意味になります。

TRIMでは要件を満たせない理由

「文字列前後の空白を除去する」という要件から改修方法を考えたときに、最初は正規表現以外の方法でできないかと考えました。(正規表現には苦手意識があり…)

今回は文字列前後の空白のみを除去したく、文字間の空白はそのまま残したかったことから、REPLACEなどで置換する方法は諦めました。

それならばTRIM関数はどうだろうとあれこれ調べてみましたが、結論としては今回の要件を完璧には満たせず、正規表現を使用するに至りました。今回TRIM関数の何がダメだったのか、メモしておきたいと思います。

TRIMは1つのパターンにしか対応できない

スペースの除去として有名(?)なのがTRIM関数。文字列前後の半角スペースを除去するだけであれば、次のように書くだけで対応できます。

TRIM(対象文字列)

しかしこの書き方では、全角スペースに対応していません。文字列前後に全角スペースがある場合は、除去されず残ってしまいます。

では次に、第二引数を指定する場合はどうでしょうか。TRIM関数は第二引数を指定することで、指定した文字列を前後から除去することができます。

TRIM(対象文字列, 除去したい文字)

たとえば、

TRIM(’(全角スペース)あいうえお’, ‘(全角スペース)’)

とした場合、実行結果は「あいうえお」となります。こうすれば全角スペースが除去されますが、今度は半角スペースが除去されなくなります。

それならばと、

TRIM(’(半角スペース)(全角スペース)あいうえお’, ‘(半角スペース)(全角スペース)’)

としてみました。これでも、文字列先頭の「半角スペース+全角スペース」は除去されます。しかし今回のパターンは、もはや無限。

  • 半角スペース
  • 全角スペース
  • 半角スペース+全角スペース
  • 全角スペース+半角スペース
  • 半角スペース2つ
  • 全角スペース2つ
  • 半角スペース+全角スペース+半角スペース

などなど…。

これらすべてに対応できるわけがなく、TRIMは諦めました。(そもそもこんなデータが混在していることが問題なのでは、というのはさておき)

LTRIMとRTRIMでも対応できないパターンがある

あれこれ調べてみると、下記のような書き方もできるようです。

RTRIM(LTRIM(TRIM(‘  ABC  ‘), ‘ ’), ‘ ’)

RTRIMは文字列の右側、つまりは末尾に指定した文字列があれば削除します。

LTRIMは文字列の左側、つまりは先頭に指定した文字列があれば削除します。

この場合、TRIMで文字列前後の半角スペースが除去されてから、LTRIMで文字列先頭の全角スペースを除去し、RTRIMで文字列末尾の全角スペースを除去しています。

TRIMだけを使うよりもうまくいくパターンが多いのですが、こちらについても完ぺきではなく…。半角スペースと全角スペースがサンドウィッチのように挟まり合っている状態の場合は、除去しきれないので、今回の使用は見送りとなりました。

教えてchatGPT!私のプロンプト

今回の正規表現は、chatGPT先生に聞いて教えてもらいました。参考までに、私がこの方法を教えてもらえたプロンプト(chatGPTへの質問)を記載しておきます。

あなたはOracleDBマスターです。
PL/SQLの作成を手伝っていただけますでしょうか。

やりたいこととしては、文字列前後の空白を除去したいというものになります。
空白は全角スペースと半角スペースの両方を含みます。
文字列の間に挟まっているスペースについては除去せず、そのままにしてほしいです。
また、全角スペースや半角スペースは必ずしも1つというわけではなく、
全角スペースが2つ重なっていたり、半角スペースと全角スペースが隣り合って出力されているケースもあります。

例)    あいう え お
↓希望している形
あいう え お

そんなにすっきりとした聞き方はできていませんが、こんな質問でもパッと正規表現を教えて貰えました。やはりchatGPT先生は優秀ですね…!ありがたい存在です。

まとめ

Oracleで空白を除去するといえばTRIM関数!というイメージでしたが、TRIM関数だけでは半角スペースや全角スペースが混在しているパターンに対応できないことがわかりました。

正規表現は私にとって難解で、なかなか自分だけで作成するのがまだ難しいのですが(6年目エンジニアなのに…)、chatGPT先生のおかげでかなり楽になりましたね。感謝感謝です。

  • 文字列前後の空白(半角スペース、全角スペース、混在も含む)を除去したい
  • 文字間の空白は除去したくない

こういった要件であれば、下記の正規表現で実現可能です。

SELECT REGEXP_REPLACE(対象文字列, ‘^[  ]+|[  ]+$’, )
FROM dual;

この記事がどなたかのお役に立てれば幸いです。ありがとうございました!