web-dev-qa-db-ja.com

PostgreSQLで末尾のスペースを削除する

末尾のスペースを含む列eventDateがあります。 PostgreSQL関数TRIM()でそれらを削除しようとしています。より具体的には、私は実行しています:

SELECT TRIM(both ' ' from eventDate) 
FROM EventDates;

ただし、末尾のスペースは消えません。さらに、日付から別の文字(数値など)をトリムしようとしても、トリムされません。 マニュアル を読んでいる場合、これは正しく機能するはずです。何かご意見は?

32
zgall1

多くの異なる不可視文字があります。それらの多くは、UnicodeでプロパティWSpace=Y( "whitespace")を持っています。ただし、一部の特殊文字は「空白」とは見なされず、表示可能な表現はありません。 スペース(句読点) および 空白文字 に関するWikipediaの優れた記事をご覧ください。

<rant> Unicodeはこの点で悪い:主に人々を混乱させるのに役立つ多くのエキゾチックなキャラクターを導入する。</ rant>

標準SQL trim() function デフォルトでは、基本的なラテン語スペース文字のみをトリムします(Unicode:U + 0020/ASCII 32)。 rtrim() and ltrim() variant。呼び出しはその特定の文字のみをターゲットにします。

代わりに regexp_replace() で正規表現を使用してください。

末尾

削除するすべての末尾空白(ただし、空白内部文字列ではありません):

SELECT regexp_replace(eventdate, '\s+$', '') FROM eventdates;

正規表現の説明:
\s .. [[:space:]]の正規表現クラスの略記
-これは空白文字のセットです-以下の制限を参照してください
+ .. 1つ以上の連続した一致
$ ..文字列の終わり

デモ:

SELECT regexp_replace('inner white   ', '\s+$', '') || '|'

戻り値:

inner white|

はい、それはsingleバックスラッシュ(\)です。この関連する回答の詳細。

一流

先行するすべての空白(ただし、文字列内の空白は除く)を削除するには:

regexp_replace(eventdate, '^\s+', '')

^ ..文字列の開始

両方

bothを削除するには、上記の関数呼び出しを連鎖できます。

regexp_replace(regexp_replace(eventdate, '^\s+', ''), '\s+$', '')

または、1つの呼び出しで両方を2つの branches と組み合わせることができます。
4番目のパラメーターとして'g'を追加して、最初の一致だけでなく、すべての一致を置換します。

regexp_replace(eventdate, '^\s+|\s+$', '', 'g')

ただし、通常は substring() を使用すると高速になります。

substring(eventdate, '\S(?:.*\S)*')

\S ..すべてしかし空白
(?:re)非キャプチャー括弧セット
.* .. 0-n文字の文字列

または次のいずれか:

substring(eventdate, '^\s*(.*\S)')
substring(eventdate, '(\S.*\S)')

(re) .. 括弧のセットのキャプチャ

効果的に、最初の非空白文字と、使用可能な場合は最後の非空白文字までのすべてを取得します。

空白?

さらにいくつかあります nicodeで「空白」として分類されない関連文字 -したがって、文字クラス[[:space:]]には含まれません。

これらはpgAdminで不可視のグリフとして印刷されます: "mongolian vowel"、 "zero width space"、 "zero width non-joiner"、 "zero width joiner":

SELECT E'\u180e', E'\u200B', E'\u200C', E'\u200D';

'᠎' | '​' | '‌' | '‍'

さらに2つ、pgAdminではvisibleグリフとして印刷されますが、ブラウザーでは表示されません: "Word joiner"、 "zero width non-breaking space":

SELECT E'\u2060', E'\uFEFF';
'⁠' | ''

最終的に、文字が不可視にレンダリングされるかどうかは、表示に使用されるフォントにも依存します。

これらすべても削除するには、'\s''[\s\u180e\u200B\u200C\u200D\u2060\uFEFF]'または'[\s᠎​‌‍⁠]'(末尾の見えない文字に注意してください!)に置き換えます。
例、代わりに:

regexp_replace(eventdate, '\s+$', '')

つかいます:

regexp_replace(eventdate, '[\s\u180e\u200B\u200C\u200D\u2060\uFEFF]+$', '')

または:

regexp_replace(eventdate, '[\s᠎​‌‍⁠]+$', '')  -- note invisible characters

制限事項

Posix文字クラス[[:graph:]] も「可視文字」を表すと想定されています。例:

substring(eventdate, '([[:graph:]].*[[:graph:]])')

すべてのセットアップでASCII文字([\x21-\x7E]に要約される))に対して確実に動作しますが、それ以上は(基本ページ10を含む)基本OSによって提供される情報に依存します(ctype)および場合によってはロケール設定。

厳密に言えば、それはeveryの文字クラスへの参照の場合ですが、graphのようなあまり一般的に使用されていないものとの不一致があるようです。ただし、すべての空白文字をキャッチするには、文字クラス[[:space:]](省略形\s)にさらに文字を追加する必要がある場合があります。 例:\u2007\u202f\u00a0は@XiCoN JFSでも欠落しているようです

マニュアル:

ブラケット式内で、[:および:]で囲まれた文字クラスの名前は、そのクラスに属するすべての文字のリストを表します。標準の文字クラス名:alnumalphablankcntrldigitgraphlowerprintpunctspaceupperxdigit。これらは、ctypeで定義された文字クラスを表します。ロケールは他のものを提供できます。

大胆な強調鉱山。

Postgres 10で修正済み であったこの制限にも注意してください:

大きな文字コード、特にU+7FFより上のUnicode文字の正規表現の文字クラス処理を修正しました。(Tom Lane)

以前は、そのような文字は、[[:alpha:]]などのロケール依存の文字クラスに属するものとして認識されることはありませんでした。

61

空白がspaceメタ値だけではない場合、regexp_replaceを使用する必要があります。

 SELECT '(' || REGEXP_REPLACE(eventDate, E'[[:space:]]', '', 'g') || ')' 
 FROM EventDates;

上記の例では、()に戻り値をバインドしているので、簡単にseeで正規表現の置換がpsqlプロンプトで機能していることがわかります。そのため、コードからこれらを削除する必要があります。

2
Cody Caughlan

それはあなたがそれを扱っている方法で動作するはずですが、特定の文字列を知らずに言うのは難しいです。

先行スペースのみをトリミングする場合は、より簡潔な形式を使用できます。

SELECT RTRIM(eventDate) 
FROM EventDates;

これは 小さなテスト であり、動作することを示しています。うまくいったら教えてください!

2
ArthurChamz
SELECT  replace(('       devo    system      ') ,' ','');

devosystemを与えます

0
devosystem sarl