【问题标题】:Select rows where first, last or both characters are special or punctuation, unless they only have a period at the end选择第一个、最后一个或两个字符都是特殊字符或标点符号的行,除非它们的末尾只有句点
【发布时间】:2025-12-28 00:00:11
【问题描述】:

我需要从表中检索名称以[:space:] 或其他特殊字符[:punct:] 开头或结尾的行,不包括名称末尾的单个点(.)。这个想法是提取可能不一致的名称。

必须出现的示例:

  1. 'GEORGE & SON ' - 最后有一个额外的空间。
  2. '-GEORGE & SON' - 开头有一个额外的 -
  3. '&GEORGE & SON' - 开头有一个额外的 &
  4. '-GEORGE & SON S.A.' - 开头有一个额外的-。最后的点. 不是问题。
  5. 'GEORGE & SON..' - 最后没有一个点,而是两个点。以多个. 结尾的字符串除外;他们也是坏名声。

不能出现的例子:

  1. 'GEORGE & SON.' - 最后只有一个额外的“.”。

我正在使用表达式:

REGEXP_LIKE(col, '(^[[:punct:]]|[[:punct:]]$)|(^[[:space:]]|[[:space:]]$)')

但尽管检索以空格或特殊字符开头或结尾的名称,但也会拉出带有点 '.' 的名称。作为最后一个字符。

我怎样才能改变它以获得我需要的结果?

【问题讨论】:

    标签: sql oracle regexp-like


    【解决方案1】:

    由于预定义的标点字符类不适用于字符串的末尾,因此使用自定义字符类代替。故意留下点。单独添加单引号(因为转义它不起作用并且在这种情况下可能很难为 q 运算符找到正确的字符)。自行添加右方括号,因为 Oracle 在转义时似乎无法正确处理它。最后显式添加尾随的连续点:

    WITH T (id, col) AS (
      SELECT 1, 'GEORGE & SON ' FROM DUAL UNION ALL
      SELECT 2, '-GEORGE & SON'  FROM DUAL UNION ALL
      SELECT 3, '&GEORGE & SON'  FROM DUAL UNION ALL
      SELECT 4, 'GEORGE & SON..'  FROM DUAL UNION ALL
      SELECT 5, 'GEORGE & SON.'  FROM DUAL UNION ALL
      SELECT 6, '-GEORGE & SON S.A.' FROM DUAL UNION ALL
      SELECT 7, 'GEORGE & SON!' FROM DUAL UNION ALL
      SELECT 8, 'GEORGE & SON"' FROM DUAL UNION ALL
      SELECT 9, 'GEORGE & SON#' FROM DUAL UNION ALL
      SELECT 10, 'GEORGE & SON$' FROM DUAL UNION ALL
      SELECT 11, 'GEORGE & SON%' FROM DUAL UNION ALL
      SELECT 12, 'GEORGE & SON&' FROM DUAL UNION ALL
      SELECT 13, 'GEORGE & SON(' FROM DUAL UNION ALL
      SELECT 14, 'GEORGE & SON)' FROM DUAL UNION ALL
      SELECT 15, 'GEORGE & SON*' FROM DUAL UNION ALL
      SELECT 16, 'GEORGE & SON+' FROM DUAL UNION ALL
      SELECT 17, 'GEORGE & SON,' FROM DUAL UNION ALL
      SELECT 18, 'GEORGE & SON\' FROM DUAL UNION ALL
      SELECT 19, 'GEORGE & SON-' FROM DUAL UNION ALL
      SELECT 20, 'GEORGE & SON\' FROM DUAL UNION ALL
      SELECT 21, 'GEORGE & SON/' FROM DUAL UNION ALL
      SELECT 22, 'GEORGE & SON:' FROM DUAL UNION ALL
      SELECT 23, 'GEORGE & SON;' FROM DUAL UNION ALL
      SELECT 24, 'GEORGE & SON<' FROM DUAL UNION ALL
      SELECT 25, 'GEORGE & SON=' FROM DUAL UNION ALL
      SELECT 26, 'GEORGE & SON>' FROM DUAL UNION ALL
      SELECT 27, 'GEORGE & SON?' FROM DUAL UNION ALL
      SELECT 28, 'GEORGE & SON@' FROM DUAL UNION ALL
      SELECT 29, 'GEORGE & SON[' FROM DUAL UNION ALL
      SELECT 30, 'GEORGE & SON^' FROM DUAL UNION ALL
      SELECT 31, 'GEORGE & SON_' FROM DUAL UNION ALL
      SELECT 32, 'GEORGE & SON`' FROM DUAL UNION ALL
      SELECT 33, 'GEORGE & SON{' FROM DUAL UNION ALL
      SELECT 34, 'GEORGE & SON|' FROM DUAL UNION ALL
      SELECT 35, 'GEORGE & SON}' FROM DUAL UNION ALL
      SELECT 36, 'GEORGE & SON~' FROM DUAL UNION ALL
      SELECT 37, 'GEORGE & SON''' FROM DUAL UNION ALL
      SELECT 38, 'GEORGE & SON]' FROM DUAL)
    SELECT
      * FROM T
     WHERE REGEXP_LIKE(col, '(^[[:punct:]]|[-!"#$%&()*+,\/:;<=>?@[^_`{|}~' || '''' || ']$)|]$|\.\.$|(^[[:space:]]|[[:space:]]$)')
     ORDER BY id
    ;
    

    更新要求

    标点后跟一个点

    为特殊字符集添加一个可选的点;来自

    '[-!"#$%&()*+,\/:;<=>?@[^_`{|}~' || '''' || ']$'
    

    '[-!"#$%&()*+,\/:;<=>?@[^_`{|}~' || '''' || ']\.?$'
    

    WITH T (id, col) AS (
      SELECT 40, 'GEORGE & SON^.'FROM DUAL UNION ALL
      SELECT 41, 'GEORGE & SON_.'FROM DUAL UNION ALL
      SELECT 42, 'GEORGE & SON`.'FROM DUAL UNION ALL
      SELECT 43, 'GEORGE & SON{.'FROM DUAL UNION ALL
      SELECT 44, 'GEORGE & SON|.'FROM DUAL UNION ALL
      SELECT 45, 'GEORGE & SON}.'FROM DUAL UNION ALL
      SELECT 46, 'GEORGE & SON~.'FROM DUAL UNION ALL
      SELECT 47, 'GEORGE & SON''.'FROM DUAL UNION ALL
      SELECT 48, 'GEORGE & SON].'FROM DUAL)
    SELECT
      * FROM T
     WHERE REGEXP_LIKE(col, '([-!"#$%&()*+,\/:;<=>?@[^_`{|}~' || '''' || ']\.?$)|]\.?$')
     ORDER BY id
    ;
    

    字符串中空格和特殊字符(组合)的重复

    最初,只要求出现前导和尾随事件……;-)

    两个或多个空格/标点字符的序列被

    捕获
    [[:space:][:punct:]]{2,}
    

    如果你想在字符串中明确地使用它,只需 - 用单词字符包围它们:

    \w[[:space:][:punct:]]{2,}\w
    

    当找到单个空格时,前导/尾随连续空格已经匹配 - 无需明确担心它们。
    这给出了:

    WITH T (id, col) AS (
      SELECT 50, 'GEORGE & SON  ' FROM DUAL UNION ALL
      SELECT 51, 'GEORGE & SON   '  FROM DUAL UNION ALL
      SELECT 52, '  GEORGE & SON'  FROM DUAL UNION ALL
      SELECT 53, '    GEORGE & SON'  FROM DUAL UNION ALL
      SELECT 54, 'GEORGE &  SON'  FROM DUAL UNION ALL
      SELECT 55, 'GEORGE  & SON S.A.' FROM DUAL UNION ALL
      SELECT 56, 'GEORGE & SON    S.A.' FROM DUAL UNION ALL
      SELECT 60, '  GEORGE and SON'  FROM DUAL UNION ALL
      SELECT 61, ' ,GEORGE and SON' FROM DUAL UNION ALL
      SELECT 62, ', GEORGE and SON'  FROM DUAL UNION ALL
      SELECT 63, 'GEORGE -- SON' FROM DUAL UNION ALL
      SELECT 64, 'GEORGE --SON' FROM DUAL UNION ALL
      SELECT 65, 'GEORGE & SON' FROM DUAL UNION ALL
      SELECT 66, 'GEORGE + SON' FROM DUAL UNION ALL
      SELECT 67, 'GEORGE and  , SON' FROM DUAL UNION ALL
      SELECT 68, 'GEORGE and , SON' FROM DUAL UNION ALL
      SELECT 69, 'GEORGE and SON ,'  FROM DUAL UNION ALL
      SELECT 70, 'GEORGE and SON. '  FROM DUAL UNION ALL
      SELECT 71, 'GEORGE and+-SON'  FROM DUAL)
    SELECT
      * FROM T
    --  WHERE REGEXP_LIKE(col, '(^[[:punct:]]|[-!"#$%&()*+,\/:;<=>?@[^_`{|}~' || '''' || ']\.?$)|]$|\.\.$|(^[[:space:]]|[[:space:]]$)|[[:space:][:punct:]]{2,}')
      WHERE REGEXP_LIKE(col, '(^[[:punct:]]|[-!"#$%&()*+,\/:;<=>?@[^_`{|}~' || '''' || ']\.?$)|]$|\.\.$|(^[[:space:]]|[[:space:]]$)|\w[[:space:][:punct:]]{2,}\w')
      ORDER BY id
    ;
    

    但是这会产生误报,最突出的是GEORGE & SON。在某种程度上,可以通过将 [:punct:] 替换为包含较少的集合来避免这种情况。 (最终)选择将取决于更令人担忧的是假阴性还是假阳性。

    查看实际操作:

    捕获任意序列的标点符号和空格字符 - 但允许单个字母后跟一个点和一个空格

    如前所述,误报需要与误报相平衡。一种方式或另一种方式。 然而,这可能是考虑将整体问题分解为更小的问题并单独处理它们的好时机。即使 GEORGE and P. SON 是完全可以接受的,您也可能想要查看,例如 -GEORGE and P. SON。因此,让我们专注于字符串中间的杂散字符序列 - 甚至记住之前的 ** 和 **,并允许枚举(因此允许使用逗号):

    WHERE
      REGEXP_LIKE(col, '\w[[:space:][:punct:]]{2,}\w')
      AND
      NOT REGEXP_LIKE(col, ' [[:upper:]]\. \w')
      AND
      NOT INSTR(col, ', ') > 0
      AND
      NOT INSTR(col, ' & ') > 0
    

    可能紧随其后

      WHERE
      REGEXP_LIKE(col, '\w[[:space:][:punct:]]{2,}\w')
      AND
      (REGEXP_LIKE(col, ' [[:upper:]]\. \w')
       OR
       INSTR(col, ', ') > 0
       OR
       INSTR(col, ' & ') > 0
      )
    

    为了在许多有效的之间找到例如 GEORGE 和 , SONINSTR 可能比 REGEX 更快 - 取决于整体情况……

    关于机制的更多信息

    (i) [[:punct:][:space:]] 本质上结合了 [[:punct:]][[:space: ]] 到单个字符类中。就该类的选择而言,顺序无关紧要。

    (ii)

    [-!"#$%&()*+,\/:;<=>?@[^_`{|}~' || '''' || ']
    

    [-!"#$%&()*+,\/:;<=>?@[^_`{|}~]
    

    添加了单引号。如果直接尝试,Oracle 会考虑使用单引号来结束参数值。并且用反斜杠转义单引号不起作用......所以基本上,这就是上面所说的“单独添加单引号”。

    如果需要调整/进一步详细信息,请发表评论。

    【讨论】:

    • AbeCee 的好主意。非常非常非常感谢。问题太复杂了。我注意到仍然没有 fech 'GEORGE & SON '。空格和'\.'的组合NOR 包括在 {2 or more} 的完整字符串中重复的可能性,对于 [:space:]、[:punct:] 或两者之间的组合,检索:'GEORGE SON' - ( ' ') [:space:]{2 或更多} 'GEORGE SON' - ('') [:punct:]{2 或更多} 'GEORGE SON' - (' * ') [:space:] and [:punct:]{2 or more} 'GEORGE SON' - (' ' or ' ' or ' * ') [:space:] 和 [:punct:]{2 个或更多}
    • @LEOPOLDO 你提到的一些/大部分内容可以很容易地用量词来满足。只需扩展您问题中的示例列表 - 并且可能在 SQL Fiddle 中。可能无法轻松捕获所有案例(使用单个 WHERE 子句) - 但仍会让您有更多候选人进行审查。
    • 你能插入其中一个,作为例子,让我理解吗?
    • 优秀的阿贝西,亲爱的朋友。我会测试并让你知道早上的第一件事。我向您致以最诚挚的问候,并感谢您的时间和知识。
    • 嗨,阿贝西。我非常感谢大家的支持。我可以再提两个问题吗?你说过'[[:space:][:punct:]]{2,} 捕获两个或多个空格/标点字符的序列。 我的问题是1)**这是双向的吗?空格/标点和标点/空格!!! - **2) 请您解释一下字符集 '([-!"#$%&()*+,\/:; 的含义?@[^_`{|}~' || '''' || ']\.?$)|]\.?$'。我是正则表达式的菜鸟,不知道 - 例如- 集合 '|| '''' ||' 的含义。再次感谢你。
    【解决方案2】:

    只需在第二个 [[:punct:]] 之后添加 {2} 即可。这意味着点应该至少出现 2 次​​p>

    with tab as(
      select 'GEORGE & SON ' as s from dual union all
      select '-GEORGE & SON'  as s from dual union all
      select '&GEORGE & SON'  as s from dual union all
      select 'GEORGE & SON..'  as s from dual union all
      select 'GEORGE & SON.'  as s from dual union all
      select '-GEORGE & SON S.A.' as s from dual  
    )
    select * from  tab 
    where REGEXP_LIKE(s, '(^[[:punct:]]|[[:punct:]]{2}$)|(^[[:space:]]|[[:space:]]$)') 
    

    【讨论】:

    • 这将忽略末尾的任何单个标点符号 - 例如,它不会匹配 'GEORGE &amp; SON&amp;'。我认为只有句号需要特殊处理,结尾不需要任何标点符号?
    • @AlexPoole 我是从这些例子中得出的。但你是对的,这种情况不会被匹配
    • 你说得对,亚历克斯·普尔。需要获取所有具有无效客户端名称的行; [以]> [:Punct:]{1 或更多} OR [:space:]{1 或更多} 结尾,不包括后跟“点”的 [:alpha:]。 [开头]> [:Punct:]{1 个或多个} OR [:space:]{1 个或多个}。 [完整字段]> [:Punct:]{2 个或更多} OR [:space:]{2 个或更多}。
    • 嗨,阿贝西。我真诚地祝愿你和像你这样的人,作为大帮手来到我们身边。我测试并注意到正则表达式没有捕捉到“GEORGE**:punct:**SON。在单词之间获取一个标点字符,其中只允许 '-'。我知道我没有请求它,但在你的宝贵帮助下,我已经能够构建一组解决我的问题的角色。所以 - “GEORGE#SON”应该被抓住,“GEORGE-SON”不应该。我很高兴你善良和耐心。谢谢。这是我的第一个问题,我该如何关闭它?
    最近更新 更多