正则表达式填充零

And*_*own 1 regex sql postgresql natural-sort

我的表中有一系列字符串,我想订购.例如.

Chapter 1 
Chapter 2 
Chapter 11 
Chapter 12
Run Code Online (Sandbox Code Playgroud)

要正确地订购它,我需要用零填充它们.

Chapter 001 
Chapter 002 
Chapter 011 
Chapter 012
Run Code Online (Sandbox Code Playgroud)

也许我可以使用regexp_replace()正则表达式在零中使用pad.

  regexp_replace(chapters.name,'(\d+)\D*','0\1') as name
Run Code Online (Sandbox Code Playgroud)

此解决方案不起作用.我想也许我可以弄清楚反向引用的长度并使用该数字填充我需要的东西:

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

\1length()总是返回2,即使我使用注意到\1在某些Postgres的功能转化\1为实际捕获的数据.

如何使用Postgres字符串函数和Postgres正则表达式填充零?

Erw*_*ter 5

问题

你的第二次尝试是两个误解的受害者:

  • 的第二个参数lpad()rpad()得到总长度,不字符的数量添加.

  • 你感到困惑的范围regexp_replace()与范围lpad().lpad()首先执行,\l\1没有特殊意义lpad().

解决方案

这是一个"自然排序"的问题.相关回答:

正如那里所建议的那样,最好的解决方案是存储标准化数据.如果前导'Chapter'实际上是所有值中的不可变字符串,则不要存储它,只将数字部分存储为integer.

如果您的示例值是准确的,我们可以忽略前导常量文本,只是按尾随数字排序.比任何重新格式化字符串的尝试要快得多:

SELECT *
FROM   chapters
ORDER  BY split_part(name, ' ', 2)::int
Run Code Online (Sandbox Code Playgroud)

如果您确实需要零填充字符串,并且前导文本可能会有所不同:

SELECT split_part(name, ' ', 1) || ' '
    || lpad(split_part(name, ' ', 2), 3,  '0')
FROM   chapters
ORDER  BY 1;
Run Code Online (Sandbox Code Playgroud)

SQL小提琴.

两个函数调用加上连接,但仍然比regexp_replace().正则表达式相对昂贵.
更多示例lpad():