Регулярное выражение для заполнения нулями

У меня есть ряд строк в моей таблице, которые я хочу заказать. например.

Chapter 1 
Chapter 2 
Chapter 11 
Chapter 12

Чтобы упорядочить их правильно, мне нужно было бы дополнить их нулями.

Chapter 001 
Chapter 002 
Chapter 011 
Chapter 012

Может быть, я могу использовать regexp_replace() дополнение нулями с использованием регулярного выражения.

  regexp_replace(chapters.name,'(\d+)\D*','0\1') as name

Это решение не работает. Я подумал, что, может быть, я смогу вычислить длину обратной ссылки и использовать это число, чтобы дополнить то, что мне нужно:

  regexp_replace(chapters.name,'(\d+)\D*',lpad('\l',3-length('\1'),'0') as name

но \1 в length() всегда возвращает 2, хотя я заметил, что использование \1 в определенной функции postgres переводит \1 в фактические захваченные данные.

Как добавить нули, используя строковые функции Postgres и регулярное выражение Postgres?


person Andrew WC Brown    schedule 17.02.2015    source источник


Ответы (1)


Проблемы

Ваша вторая попытка является жертвой двух недоразумений:

  • Второй параметр lpad() и rpad() — это результирующая общая длина, а не количество символов для добавления.

  • Вы путаете область действия regexp_replace() с областью действия lpad(). lpad() выполняется первым, а \l и \1 не имеют особого значения для lpad().

Решения

Это проблема естественного характера. Связанный ответ:

Как советовали там, лучшим решением было бы для начала хранить нормализованные данные. Если начальный «Chapter» на самом деле является неизменяемой строкой во всех значениях, не сохраняйте ее вообще, а просто сохраните числовую часть как integer.

Если значения вашего примера точны, мы можем игнорировать начальный постоянный текст и просто сортировать по конечному номеру. Гораздо быстрее, чем любая попытка переформатирования строк:

SELECT *
FROM   chapters
ORDER  BY split_part(name, ' ', 2)::int

Если вам действительно нужны строки, заполненные нулями, а начальный текст может варьироваться:

SELECT split_part(name, ' ', 1) || ' '
    || lpad(split_part(name, ' ', 2), 3,  '0')
FROM   chapters
ORDER  BY 1;

SQL Fiddle.

Два вызова функций плюс конкатенация, но все же быстрее, чем regexp_replace(). Регулярные выражения сравнительно дороги.
Еще примеры для lpad():

person Erwin Brandstetter    schedule 17.02.2015
comment
Это поставило меня на правильный путь. Данные, которые у меня были, были не очень чистыми. В некоторых строках было несколько пробелов. Там тоже было 3 слова. Я мог бы использовать несколько split_parts, или подстроку, или что-то еще. Во всяком случае, я использовал: select mapname, regexp_replace(mapname,'[ ]+[0-9].*',' ') || lpad(regexp_replace(mapname,'(.*)[ ]+([0-9].*)','\2'), 3, '0') from mapextents where maptype ~ 'grids' для этого "Map Index 94";"Map Index 094" "Map Index 95";"Map Index 095" "Map Index 100";"Map Index 100" - person Bryan; 23.06.2017