Подтвердить что ты не робот

Обрезать конечные пробелы с помощью PostgreSQL

У меня есть столбец eventDate, который содержит конечные пробелы. Я пытаюсь удалить их с помощью функции PostgreSQL TRIM(). В частности, я запускаю:

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

Однако конечные пробелы не исчезают. Кроме того, когда я пытаюсь урезать другой символ с даты (например, число), он не обрезает ни один из них. Если я правильно читаю руководство, это должно сработать. Любые мысли?

4b9b3361

Ответ 1

Есть много разных невидимых персонажей. Многие из них имеют свойство WSpace=Y ("пробел") в Unicode. Но некоторые специальные символы не считаются "пробелами" и все еще не имеют видимого представления. Отличная статья в Википедии о пробелах и знаках пробела должна дать вам представление.

<rant> Unicode отстой в этом отношении: вводит множество экзотических персонажей, которые в основном служат, чтобы сбить с толку людей. </rant>

Стандартная функция SQL trim() по умолчанию обрезает только основной латинский пробел (Unicode: U + 0020/ASCII 32). То же самое с rtrim() и ltrim(). Ваш звонок также касается только этого конкретного персонажа.

regexp_replace() этого используйте регулярные выражения с regexp_replace().

Скользящий

Чтобы удалить все конечные пробелы (но не пробелы внутри строки):

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

Регулярное выражение объясняет:
\s.. сокращение класса регулярного выражения для [[:space:]]
- который представляет собой набор символов пробела - см. ограничения ниже
+.. 1 или более последовательных матчей
$.. конец строки

Демо-версия:

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

Возвращает:

inner white|

Да, это один обратный слеш (\). Подробности в этом связанном ответе.

ведущий

Чтобы удалить все начальные пробелы (но не пробелы внутри строки):

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

^.. начало строки

И то и другое

Чтобы удалить оба, вы можете связать вышеупомянутые вызовы функций:

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

Или вы можете объединить оба в одном вызове с двумя ответвлениями.
Добавьте 'g' качестве 4-го параметра, чтобы заменить все совпадения, а не только первый:

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

Но обычно это происходит быстрее с substring():

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

\S.. все, кроме пустого пространства
(?: re ) Набор без скобок
.*.. любая строка из 0-n символов

Или один из них:

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

( re ).. Захват набор скобок

Эффективно принимает первый непробельный символ и все до последнего непробельного символа, если он доступен.

Пробелы?

Есть еще несколько связанных символов, которые в Unicode не классифицируются как "пробел", поэтому они не содержатся в классе символов [[:space:]].

Они печатаются как невидимые символы в pgAdmin для меня: "монгольская гласная", "пробел нулевой ширины", "не присоединяющийся к нулевой ширине", "соединитель с нулевой шириной":

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

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

Еще два, печать в виде видимых глифов в pgAdmin, но невидимых в моем браузере: "Word Joiner", "Неразрывный пробел нулевой ширины":

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) зависите от информации, предоставленной базовой ОС (для определения ctype) и возможно настройки локали.

Строго говоря, так обстоит дело с каждой ссылкой на класс символов, но, похоже, больше разногласий с менее часто используемыми, такими как graph. Но вам может понадобиться добавить больше символов в класс символов [[:space:]] (сокращение \s), чтобы перехватить все пробельные символы. Например: \u2007, \u202f и \u00a0 также отсутствуют в @XiCoN JFS.

Руководство:

В выражении в скобках имя класса символов, заключенное в [: и :] обозначает список всех символов, принадлежащих этому классу. Стандартные имена классов символов: alnum, alpha, blank, cntrl, digit, graph, lower, print, punct, space, upper, xdigit. Они обозначают классы символов, определенные в ctype. Локаль может предоставить другим.

Жирный акцент мой.

Также обратите внимание на это ограничение, которое было исправлено в Postgres 10:

Исправлена обработка класса символов регулярных выражений для кодов больших символов, особенно символов Юникода выше U+7FF (Том Лейн)

Ранее такие символы никогда не распознавались как принадлежащие классам символов, зависящим от локали, таким как [[:alpha:]].

Ответ 2

Он должен работать так, как вы его обрабатываете, но это трудно сказать, не зная конкретной строки.

Если вы только обрезаете ведущие пробелы, вы можете использовать более сжатую форму:

SELECT RTRIM(eventDate) 
FROM EventDates;

Это маленький тест, чтобы показать вам, что он работает. Скажите нам, если это сработает!

Ответ 3

Если ваше пробелы больше, чем только метатеги space, чем вам нужно будет использовать regexp_replace:

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

В приведенном выше примере я ограничиваю возвращаемое значение в ( и ), чтобы вы могли видеть, что замена регулярного выражения работает в командной строке psql. Поэтому вы захотите удалить их в своем коде.

Ответ 4

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

Это дает: devosystem