【问题标题】:Removing a list of keywords from string从字符串中删除关键字列表
【发布时间】:2021-12-09 07:13:55
【问题描述】:

我有一个包含文本块的数据列。例如,“John Doe 住在翡翠街”。我想从字符串中删除文本列表。我有一些这样的清单(生活,在,街道)。我想选择一个新的数据列,将文本转换为“John Doe Emerald”。

【问题讨论】:

  • 您必须更加具体。准确定义单词分隔符。如何处理空白?单词可以包含分隔符吗? Postgres 版本?文本和列表中的最大/最小/平均字数。替换顺序可能很重要......表中有多少行?理想情况下,一个基本的表定义、一些示例数据和所需的结果。

标签: postgresql


【解决方案1】:

首先你可以基于replace函数创建一个AGGREGATE函数:

CREATE OR REPLACE FUNCTION replace(x text, y text, old_txt text, new_txt text)
RETURNS text LANGUAGE sql IMMUTABLE AS
$$
    SELECT replace(COALESCE(x,y), old_txt, new_txt)
$$ ;

DROP AGGREGATE IF EXISTS replace_agg (text, text, text) CASCADE ;
CREATE AGGREGATE replace_agg (text, text, text)
(
  sfunc = replace
, stype = text
);

然后您可以在 SELECT 语句中迭代 replace_agg 函数:

SELECT replace_agg (your_table.your_column, k.keyword, '')
FROM (SELECT 'John Doe lives in Emerald Street' as your_column) as your_table
CROSS JOIN (SELECT unnest(array['lives', 'in', 'Street']) as keyword) as k

结果如下:

'John Doe   Emerald'

【讨论】:

    【解决方案2】:

    假设简单的情况:

    • 单词由一个空格字符分隔 - 在表格和替换字符串中。
    • 没有自然语言中的标点符号。没有前导或尾随噪音。
    • 区分大小写的匹配。
    • 删除所有个匹配项(而不仅仅是第一个)。

    还有一个像这样的表格:

    CREATE TABLE strings(id serial PRIMARY KEY, string text);
    
    INSERT INTO strings(string) VALUES
      ('John Doe lives in Emerald Street')
    , ('John Doe lives in Emerald Street as john DOE');
    

    regexp_replace()

    一个简短的解决方案:

    SELECT *, rtrim(regexp_replace(string, '(John|Doe|Emerald) ?', '', 'g')) FROM strings;
    

    | 在正则表达式中分隔备选分支

    相关:

    或者,将您的原始替换字符串作为输入:

    SELECT *, rtrim(regexp_replace(string, '(' || replace('John Doe Emerald', ' ', '|') || ') ?', '', 'g')) FROM strings;
    

    设置操作

    正则表达式通常很昂贵。这可能更快(最小形式):

    SELECT s.id, string_agg(word, ' ') AS string2
    FROM   strings s, unnest(string_to_array(s.string, ' ')) word
    WHERE  word <> ALL (string_to_array('John Doe Emerald', ' '))
    GROUP  BY 1
    ORDER  BY 1;
    

    为避免任何歧义并确保保留原始顺序:

    SELECT s.id, string_agg(word, ' ' ORDER BY ord) AS string2
    FROM   strings s, unnest(string_to_array(s.string, ' ')) WITH ORDINALITY AS t(word, ord)
    WHERE  t.word <> ALL (string_to_array('John Doe Emerald', ' '))
    GROUP  BY 1
    ORDER  BY 1;
    

    见:

    在单独的子查询中使用ORDER BY 通常更快:

    SELECT sub.id, string_agg(sub.word, ' ') AS string2
    FROM  (
       SELECT s.id, t.word
       FROM   strings s, unnest(string_to_array(s.string, ' ')) WITH ORDINALITY AS t(word, ord)
       WHERE  t.word <> ALL (string_to_array('John Doe Emerald', ' '))
       ORDER  BY s.id, t.ord
       ) sub
    GROUP  BY 1
    ORDER  BY 1;
    

    通常更容易与LATERAL 子查询集成:

    SELECT s.id, sub.string2
    FROM   strings s
    CROSS  JOIN LATERAL (
       SELECT string_agg(t.word, ' ' ORDER BY t.ord) AS string2
       FROM   unnest(string_to_array(s.string, ' ')) WITH ORDINALITY AS t(word, ord)
       WHERE  t.word <> ALL (string_to_array('John Doe Emerald', ' '))   
       ) sub
    ORDER  BY 1;
    

    这样,我们不需要在外部SELECT 中使用GROUP BY

    db小提琴here

    【讨论】:

      猜你喜欢
      • 2021-06-24
      • 2011-04-20
      • 1970-01-01
      • 1970-01-01
      • 2015-10-25
      • 1970-01-01
      • 2020-12-14
      相关资源
      最近更新 更多