2

我想从字符串中消除一些文本模式,我的字符串有一个管道分隔符,并且参数并不总是相互跟随。

这是我的字符串

TType=SEND|Status=OK|URL=min://j?_a=3&ver=1.1|day=3

我想消除TType=SENDURL=min://j?_a=3&ver=1.1

因此我的最终结果应该是

Status=OK|day=3

我已经尝试过。不在 postgresql中工作。

select REGEXP_REPLACE('TType=SEND|Status=OK|URL=min://j?_a=3&ver=1.1|day=3', 
'(TType=.*?(\||$))|(URL=.*?(\||$))', '')
4

5 回答 5

5

Answer:

SELECT 
REGEXP_REPLACE(
 REGEXP_REPLACE('TType=SEND|Status=OK|URL=min://j?_a=3&ver=1.1|day=3',
  '(TType|URL)=[^|]*\|?', '','g'),
'\|$', '');

Explanation:

  1. The .*? part in your pattern, although not greedy, consumes colons as well, so doesn't behave as intended. This is fixed by [^|]* that consumes any non colon character, zero or more times.

  2. Then you would also need to add the global flag 'g', in order to replace all occurences of pattern, as described in the documentation.

  3. Finally, in case a parameter you need to eliminate occurs last (since the parameters can appear in any order), you need to add an extra replacement step to eliminate a residual colon at the end of the string.

For example without the extra step, the following

SELECT
REGEXP_REPLACE('Status=OK|URL=min://j?_a=3&ver=1.1|day=3|TType=SEND',
  '(TType|URL)=[^|]*\|?', '','g');

produces

Status=OK|day=3|

while, addding the extra step, the following

SELECT 
REGEXP_REPLACE(
 REGEXP_REPLACE('Status=OK|URL=min://j?_a=3&ver=1.1|day=3|TType=SEND',
  '(TType|URL)=[^|]*\|?', '','g'),
'\|$', '');

produces the desired

Status=OK|day=3
于 2021-02-24T13:17:56.870 回答
3

分步演示:db<>fiddle

SELECT
    string_agg(elements,'|')                                                 -- 3
FROM mytable,
    regexp_split_to_table(mystring, '\|') as elements                        -- 1
WHERE split_part(elements, '=', 1) = ANY(ARRAY['TType', 'URL']) IS NOT TRUE  -- 2
  1. 将字符串拆分为参数,如A=B. 将每个移动到单独的记录中
  2. 在字符处拆分这些元素=并过滤没有 key =TType或的元素URL
  3. 最后将所有这些第一次拆分聚合到一个字符串列表中。
于 2021-02-15T15:08:09.573 回答
2

以下基于正则表达式的解决方案应该可以解决问题:

SELECT TRIM(REGEXP_REPLACE(
         'TType=SEND|Status=OK|URL=min://j?_a=3&ver=1.1|day=3', 
         '(TType|URL)=[^|]*(\||$)', '', 'g'), '|')
-- outputs:
-- Status=OK|day=3

模式的工作原理:

(TType|URL)=[^|]*(\||$)
|-----------|----|-----
1           2    3
  1. 如果任何子字符串以 any 开头TTypeURL后跟,则模式开始消耗=
  2. 模式消耗任何不是 |
  3. 该模式消耗 | 或字符串的结尾

g标志在文档中描述为

标志 g 指定替换每个匹配的子字符串,而不仅仅是第一个。

这是必要的,因为我们要替换与我们的模式匹配的所有子字符串。

最后,有时单个|字符可能会保留在字符串的末尾。任何尾随|字符都trimmed来自使用的结果TRIM

于 2021-02-24T04:09:23.620 回答
2

S-Man 的答案是有效的

当然赞成,解决方案还可以,但它不能完全满足我的问题。因为我希望解决方案在 select 和 from

如果这是“强制性”要求,那么我会看到以下选项:

  1. 创建一个函数
  2. 使用 LATERAL JOIN 将所有逻辑封闭到一个地方,相关PostgreSQL:在同一查询中使用计算列

最终查询可能如下所示:

SELECT t.*, s.result
FROM t
LEFT JOIN LATERAL (
   SELECT string_agg(elements,'|') AS result
   FROM regexp_split_to_table(t.col, '\|') as elements
   WHERE split_part(elements, '=', 1) = ANY(ARRAY['TType', 'URL']) IS NOT TRUE) s ON TRUE

db<>小提琴演示

或者通过在 SELECT 列表中使用子查询:

SELECT t.*, 
(
   SELECT string_agg(elements,'|') AS result
   FROM regexp_split_to_table(t.col, '\|') as elements
   WHERE split_part(elements, '=', 1) = ANY(ARRAY['TType', 'URL']) IS NOT TRUE
) AS result
FROM t

db<>小提琴演示 2

于 2021-02-23T19:45:37.650 回答
2

您尝试的正则表达式存在一些问题:

  1. 即使使用了非​​贪婪.*?匹配,这仍然可以包括管道符号。这可以通过使用允许除管道符号之外的任何内容的匹配器来纠正(这可能是贪婪的):[^|]*
  2. 它应该使用该'g'标志来替换所有出现,而不仅仅是第一个。
  3. 它只在末尾寻找管道,而不是在开头。这意味着如果它与最后一个管道之后的字符串匹配(即URL=...在您的示例中),它将在最后保持最后一个管道完好无损。

通过解决上述几点,这是一个工作版本:

SELECT REGEXP_REPLACE('TType=SEND|Status=OK|URL=min://j?_a=3&ver=1.1|day=3', '((Status|TType)=[^|]*[|]|[|](Status|TType)=[^|]*)', '', 'g')

Rextester 演示: https ://rextester.com/CYBP40923

于 2021-02-24T12:22:09.220 回答