具有 2 个以上不同数字和 Snowflake 语法中的一些可选字符的正则表达式字符串

Regex string with 2+ different numbers and some optional characters in Snowflake syntax

我想检查我的一个表中的特定列是否满足以下条件:

我对 Regex 有一些经验,但我对 Snowflake 的语法有疑问。每当我尝试使用 '?'正则表达式字符(将某些内容标记为可选)我收到一条错误消息。有人可以帮助我了解解决方法并提供解决方案吗?

我目前拥有的:

SELECT string, 
LENGTH(string) AS length 
    FROM tbl 
        WHERE REGEXP_LIKE(string,'^[0-9]+{3,}[-+]?[A-Z]?[a-z]?$')
    ORDER BY length;

谢谢!

假设数字需要连续,您可以使用 javascript UDF 来查找字符串中具有最多不同数字的数字:

create or replace function f(S text)
returns float
language javascript
returns null on null input 
as
$$
    const m = S.match(/\d+/g)
    if (!m) return 0
    const lengths = m.map(m=> [...new Set (m.split(''))].length)
    const max_length = lengths.reduce((a,b) => Math.max(a,b)) 
    return max_length 
$$
;

结合WHERE-clause,这就是你想要的,我相信:

select column1, f(column1) max_length 
from t
where max_length>1 and length(column1)>2 and column1 rlike '[\w\d-]+';

产量:

COLUMN1                 | MAX_LENGTH
------------------------+-----------
abc123def567ghi1111_123 |          3
123                     |          3
111222                  |          2

假设输入:

create or replace table t as
select * from values ('abc123def567ghi1111_123'), ('xyz111asdf'), ('123'), ('111222'), ('abc 111111111 abc'), ('12'), ('asdf'), ('123 456'), (null);

如果数字不必连续(即计算字符串中不同的数字),则该函数甚至更简单。然后核心逻辑变为:

    const m = S.match(/\d/g)
    if (!m) return 0
    const length = [...new Set (m)].length
    return length

希望对您有所帮助!

你的正则表达式看起来有点混乱和无效,而且它看起来也不太符合你的需要。我将这个表达式读作一个字符串:

  1. 必须以一位或多位数字开头,至少3次或更多次
    • 令我困惑的部分是“+”是一个量词,它不能用 {3,} 量化,但不知何故不会为我产生错误
  2. 可以选择后跟破折号或加号
  3. 后跟一个大写字符零次或一次(根据需要返回)
  4. 后跟并以小写字符结尾零次或一次(根据需要返回)

问题

你说你的字符串必须包含 3 个字符和至少 2 个不同的数字,数字是字符,但我不确定你的意思是不是 3 个字母...

  • 您认为数字是字符吗?
  • 字符的顺序重要吗?
  • 能否举例说明您收到的错误?

备注

检查与第一个数字不同的第二个数字涉及使用反向引用的先行概念。 Snowflake 不支持反向引用。

关于使用正则表达式进行模式匹配的一个问题是顺序会有所不同。如果顺序对您不重要,那么您将有多种模式可以匹配。

例子

下面是您可以单独测试需求的每个部分的方法。我已经包括了一些 regexp_substr 函数来展示提取如何工作以检查是否再次存在。

取消注释 WHERE 子句以查看过滤后的数据集。过滤器被写成表达式,因此您可以删除 regexp_* 列的 any/all。

select randstr(36,random(123)) as r_string
    ,length(r_string) AS length
    ,regexp_like(r_string,'^[0-9]+{3,}[-+]?[A-Z]?[a-z]?$') as reg
    ,regexp_like(r_string,'.*[A-Za-z]{3,}.*') as has_3_consecutive_letters
    ,regexp_like(r_string,'.*\d+.*\d+.*') as has_2_digits
    ,regexp_substr(r_string,'(\d)',1,1) as first_digit
    ,regexp_substr(r_string,'(\d)',1,2) as second_digit
    ,first_digit <> second_digit as digits_1st_not_equal_2nd
    ,not(regexp_instr(r_string,regexp_substr(r_string,'(\d)',1,1),1,2)) as first_digit_does_not_appear_again
    ,has_3_consecutive_letters and has_2_digits and first_digit_does_not_appear_again as test
from table(generator(rowcount => 10))
//where regexp_like(r_string,'.*[A-Za-z]{3,}.*') // has_3_consecutive_letters
//    and regexp_like(r_string,'.*\d+.*\d+.*') // has_2_digits
//    and not(regexp_instr(r_string,regexp_substr(r_string,'(\d)',1,1),1,2)) // first_digit_does_not_appear_again
;