Postgresql的子串表达式

时间:2013-06-05 13:28:30

标签: sql regex postgresql

我有一个字段message,其字符串为<pika> [SOME_TEXT_WITH|ACTION] And other stuff...

我想捕捉括号内的内容。我使用以下形式:

SELECT 
  substring(message FROM '%> \[#"[A-Z_\|]+#"\] %' FOR '#') AS my_info 
FROM my_table;

但它始终失败并出现相同的错误消息:«无效的正则表达式:括号()不平衡»。我做错了什么?

2 个答案:

答案 0 :(得分:2)

就个人而言,我使用的是perl兼容的现代正则表达式而不是可怕的POSIX-esque regexp:

regress=> SELECT (regexp_matches('<pika> [SOME_TEXT_WITH|ACTION] And other stuff...', '\[(.*?)\]'))[1];
    regexp_matches     
-----------------------
 SOME_TEXT_WITH|ACTION
(1 row)

如果要使用POSIX语法,则必须始终使用相同的转义,而不是某些地方使用\而其他地方则#。例如:

regress=> SELECT substring(
            '<pika> [SOME_TEXT_WITH|ACTION] And other stuff...' 
            FROM '%#"#[%#]#"%' FOR '#'
          );
        substring        
-------------------------
 [SOME_TEXT_WITH|ACTION]
(1 row)

文档并未明确表示捕获运算符实际上是<ESCAPECHAR>",而不是#"。这同样有效,使用常规反斜杠转义:

regress=> SELECT substring(
              '<pika> [SOME_TEXT_WITH|ACTION] And other stuff...' 
              FROM '%\"\[%\]\"%' FOR '\'
          );
        substring        
-------------------------
 [SOME_TEXT_WITH|ACTION]
(1 row)

奇怪错误的原因是PostgreSQL将POSIX SIMILAR TO样式表达式转换为封面下的真实正则表达式。你的混合逃脱正则表达式:

'%> \[#"[A-Z_\|]+#"\] %' FOR '#'

正在转变为:

'.*> \\[([A-Z_\\|]+)\\] .*'

导致:

regress=> SELECT (regexp_matches('<pika> [SOME_TEXT_WITH|ACTION] And other stuff...', '.*> \\[([A-Z_\\|]+)\\] .*'))[1];
ERROR:  invalid regular expression: parentheses () not balanced

答案 1 :(得分:1)

我认为以下是您想要的:

SELECT substring(cast(message as varchar(1000)) FROM '.*\[([A-Z_\|]*)\].*'
                )
FROM my_table;