正则表达式:将整行与精确数量的重复标记相匹配

Ian*_*lor 5 regex regex-lookarounds

我正在尝试编写一个正则表达式,它只能匹配那些每个空格分隔的标记恰好出现两次的行,无论顺序如何。

例如,以下整行应该匹配:

1 1 2 2
100 10 10 100
A B B A 
HELLO HELLO
Run Code Online (Sandbox Code Playgroud)

以下行不应匹配:

hello hello hello
1 1 22
1001
Run Code Online (Sandbox Code Playgroud)

尽管我能够使用 regex 匹配给定行中的各个重复组(\d+)(?=.*(\1)),但我很难使用^$. 我的猜测是,当我使用前瞻时,这会创建一个无限循环,我们不断地查看每个标记(包括重复)并期望稍后在字符串中重复,尽管我不确定如何解决这个问题。有任何想法吗?谢谢!

[编辑]:根据评论中的问题添加一些细节:显然,在大多数编程语言中将其实现为函数是相当简单的。然而,我最初希望将其实现为正则表达式,因为我试图匹配数据库中的某些记录。因此,这个正则表达式旨在作为 CASE 语句嵌入到 SQL 查询中,在我看来,这将是进行选择的好方法。

考虑到这种正则表达式的明显复杂性,似乎创建一个函数是可行的方法,因此几乎任何以下答案都将是很好的解决方案,具体取决于具体情况。

Nic*_*ick 3

您可以创建一个函数来分割字符串并计算其中每个单词的出现次数,true如果所有单词的计数均为 2,则返回:

create function all_pairs(v text) returns bool as $$
  with counts as (
    select count(*) as c
    from unnest(string_to_array(v, ' ')) as vals(val)
    group by val
  ),
  arr as (
    select array_agg(c) as cc
    from counts
  )
  select 2 = all(cc)
  from arr
$$ language sql
Run Code Online (Sandbox Code Playgroud)

然后您可以简单地调用该函数来测试您的字符串。例如:

with values as (
   select '1 1 2 2' as v union all
   select '100 10 10 100' union all
   select 'A B B A' union all 
   select 'HELLO HELLO' union all
   select 'hello hello hello' union all
   select '1 1 22' union all
   select '1001'
)
select * 
from values
where all_pairs(v)
Run Code Online (Sandbox Code Playgroud)

输出:

v
1 1 2 2
100 10 10 100
A B B A
HELLO HELLO
Run Code Online (Sandbox Code Playgroud)

dbfiddle.uk上的演示