如何从 PostgreSQL 中的文本中删除分隔部分?
How to remove delimited sections from text in PostgreSQL?
我想从字符串中删除一些文本模式,我的字符串有竖线分隔符,参数并不总是相互跟随。
这是我的字符串
TType=SEND|Status=OK|URL=min://j?_a=3&ver=1.1|day=3
我想消除TType=SEND
和URL=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=.*?(\||$))', '')
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
- 将字符串拆分为参数,如
A=B
。将每个移动到单独的记录中
- 在
=
字符处拆分这些元素并过滤没有键 = TType
或 URL
的元素
- 最终将所有这些第一次拆分聚合到一个字符串列表中。
是有效的
Sure upvoted, solution is okay however it does not fully satisfy my question. since i would want the solution to be within select and from
如果这是“强制性”要求,那么我会看到以下选项:
- 创建函数
- 使用 LATERAL JOIN 将所有逻辑封装到一个地方,相关 PostgreSQL: using a calculated column in the same query
最终查询可能如下所示:
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
或者使用 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
以下基于正则表达式的解决方案应该可以解决问题:
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
- 如果任何子字符串以
TType
或 URL
开头,后跟 =
,则模式开始使用
- 模式使用任何不是
|
的字符
- 模式消耗 |或字符串结尾
g
标志在documentation中被描述为
flag g specifies replacement of each matching substring rather than only the first one.
这里有必要,因为我们要替换所有与我们的模式匹配的子字符串。
最后,有时单个 |
字符可能会保留在字符串的末尾。使用 TRIM
的结果中的任何尾随 |
字符都是 trimmed
您尝试的正则表达式存在一些问题:
- 即使使用了非贪婪
.*?
匹配,这仍然可以包含管道符号。这可以通过使用允许除管道符号以外的任何内容的匹配器来纠正(这可能是贪婪的):[^|]*
- 它应该使用
'g'
标志来替换所有出现的地方,而不仅仅是第一个。
- 它只在末尾查找管道,不在开头查找。这意味着如果最后一个管道与最后一个管道之后的字符串匹配(即您的示例中的
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
答案:
SELECT
REGEXP_REPLACE(
REGEXP_REPLACE('TType=SEND|Status=OK|URL=min://j?_a=3&ver=1.1|day=3',
'(TType|URL)=[^|]*\|?', '','g'),
'\|$', '');
解释:
模式中的 .*?
部分虽然不贪心,但也会消耗冒号,因此不会按预期运行。这是由 [^|]*
修复的,它消耗任何非冒号字符,零次或多次。
然后您还需要添加全局标志 'g',以替换所有出现的模式,如 documentation.
中所述
最后,如果你需要消除的参数出现在最后(因为参数可以以任何顺序出现),你需要添加一个额外的替换步骤来消除最后一个残留的冒号字符串。
例如没有额外的步骤,如下
SELECT
REGEXP_REPLACE('Status=OK|URL=min://j?_a=3&ver=1.1|day=3|TType=SEND',
'(TType|URL)=[^|]*\|?', '','g');
生产
Status=OK|day=3|
同时,添加额外的步骤,如下
SELECT
REGEXP_REPLACE(
REGEXP_REPLACE('Status=OK|URL=min://j?_a=3&ver=1.1|day=3|TType=SEND',
'(TType|URL)=[^|]*\|?', '','g'),
'\|$', '');
产生所需的
Status=OK|day=3
我想从字符串中删除一些文本模式,我的字符串有竖线分隔符,参数并不总是相互跟随。
这是我的字符串
TType=SEND|Status=OK|URL=min://j?_a=3&ver=1.1|day=3
我想消除TType=SEND
和URL=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=.*?(\||$))', '')
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
- 将字符串拆分为参数,如
A=B
。将每个移动到单独的记录中 - 在
=
字符处拆分这些元素并过滤没有键 =TType
或URL
的元素
- 最终将所有这些第一次拆分聚合到一个字符串列表中。
Sure upvoted, solution is okay however it does not fully satisfy my question. since i would want the solution to be within select and from
如果这是“强制性”要求,那么我会看到以下选项:
- 创建函数
- 使用 LATERAL JOIN 将所有逻辑封装到一个地方,相关 PostgreSQL: using a calculated column in the same query
最终查询可能如下所示:
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
或者使用 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
以下基于正则表达式的解决方案应该可以解决问题:
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
- 如果任何子字符串以
TType
或URL
开头,后跟=
,则模式开始使用
- 模式使用任何不是
|
的字符
- 模式消耗 |或字符串结尾
g
标志在documentation中被描述为
flag g specifies replacement of each matching substring rather than only the first one.
这里有必要,因为我们要替换所有与我们的模式匹配的子字符串。
最后,有时单个 |
字符可能会保留在字符串的末尾。使用 TRIM
|
字符都是 trimmed
您尝试的正则表达式存在一些问题:
- 即使使用了非贪婪
.*?
匹配,这仍然可以包含管道符号。这可以通过使用允许除管道符号以外的任何内容的匹配器来纠正(这可能是贪婪的):[^|]*
- 它应该使用
'g'
标志来替换所有出现的地方,而不仅仅是第一个。 - 它只在末尾查找管道,不在开头查找。这意味着如果最后一个管道与最后一个管道之后的字符串匹配(即您的示例中的
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
答案:
SELECT
REGEXP_REPLACE(
REGEXP_REPLACE('TType=SEND|Status=OK|URL=min://j?_a=3&ver=1.1|day=3',
'(TType|URL)=[^|]*\|?', '','g'),
'\|$', '');
解释:
模式中的
.*?
部分虽然不贪心,但也会消耗冒号,因此不会按预期运行。这是由[^|]*
修复的,它消耗任何非冒号字符,零次或多次。然后您还需要添加全局标志 'g',以替换所有出现的模式,如 documentation.
中所述最后,如果你需要消除的参数出现在最后(因为参数可以以任何顺序出现),你需要添加一个额外的替换步骤来消除最后一个残留的冒号字符串。
例如没有额外的步骤,如下
SELECT
REGEXP_REPLACE('Status=OK|URL=min://j?_a=3&ver=1.1|day=3|TType=SEND',
'(TType|URL)=[^|]*\|?', '','g');
生产
Status=OK|day=3|
同时,添加额外的步骤,如下
SELECT
REGEXP_REPLACE(
REGEXP_REPLACE('Status=OK|URL=min://j?_a=3&ver=1.1|day=3|TType=SEND',
'(TType|URL)=[^|]*\|?', '','g'),
'\|$', '');
产生所需的
Status=OK|day=3