google-bigquery - 如何使用正则表达式提取来抓取特定字符之间的文本?
问题描述
我目前正在尝试 REGEX EXTRACT 的不同类型的公式,试图玩弄并完全理解它。下面将是我正在使用的数据的示例以及我用来获取所需内容的当前代码。(请批评我的代码,如果它可以写得更好,因为我还在学习 REGEX EXTRACT)
Sample_Data
AAAA;BBBB;CCCC;A1=1234;DDDD;EEEE
FFFF;GGGG;A1=2345;A2=4567,2345;RRRR;KKKK
SSSS;TTTT;UUUU;VVVV;A1=3456;GGGG;UUUU
UUUU:WWWW;QQQQ;IIII;A1=9876;A2=7654,7890;UUUU
我拥有的当前代码是:
SELECT
REGEXP_EXTRACT(Sample_Data, r'(?:^|;)A1=(\d*)') AS A1,
REGEXP_EXTRACT(Sample_Date, r'(?:^|;)A2=(\d*)(?:;)') AS A2,
SPLIT(REGEXP_EXTRACT(Sample_Data, r'(?:^|;)A2=(\d*\,\d*)(?:;)'), ",")[offset(1)] AS A2_v1
FROM
db.Sample
我得到的输出是:
A1 | A2 | A2_v1
1234 | NULL | NULL
2345 | 4567 | 2345
3456 | NULL | NULL
9876 | 7654 | 7890
有了输出,这就是我所期望的。但是,我有几个不同的问题,正如您在输出第 2 行中看到的那样:
2345 | 4567 | 2345
它有2345
两次,有没有办法让它只显示2345
一次,例如:
2345 | 4567 | NULL
我的思考过程是拥有 aCASE WHEN
并让它检查REGEXP_EXTRACT
公式以查看它们是否匹配以及是否确实抛出 a NULL
。有没有更好的方法来做到这一点,或者这会是最好的结果吗?
我的第二个问题是,假设我们有以下示例数据:
AAAA;GGGG;DDDD;A1=1234;A2=7890,1234,3456;DDDD
BBBB;DDDD;CCCC;FFFF;A1=2345;A2=8907,1234,4567,8976;WWWW;GGGG
CCCC;EEEE;A1=6789;A2=34567,8901,3456,12345;TTTT
使用我拥有的当前公式,它只能获得A1
和一部分A2
。但是,我如何将公式转换为能够获取所有由 分隔的数字,
?我正在寻找的最终结果如下:
A1 | A2 | A2_v1 | A2_v2 | A2_v3
1234 | 7890 | 1234 | 3456 | NULL
2345 | 8907 | 1234 | 4567 | 8976
6789 | 34567| 8901 | 3456 | 12345
我将如何使这项工作正常进行?会不会是以下内容的变体:
SPLIT(REGEXP_EXTRACT(Sample_Data, r'(?:^|;)A2=(\d*\,\d*)(?:;)'), ",")[offset(1)] AS A2_v1
和有什么不同offset
?或者是否有一种不同的公式可以做到这一点?
任何帮助将非常感激!!
解决方案
为了避免重复数字,我认为您的想法CASE ... WHEN
是一个好方法。在这种情况下,IF
条件可以用作简写。通过制作原始查询,子查询更容易比较值。
对于 A2,在 REGEXP_EXTRACT 中,您不能使用多个匹配组,因此可以通过在正则表达式中更加宽容来捕获完整的数字。例如,使用的正则表达式:
'A2=([\d,]*)'
还将匹配以下表达式:A2=1,2,3,4,5
在您的场景中可能允许也可能不允许。可以改进正则表达式以完全匹配您正在寻找的内容;但是,它需要更长的时间,或者需要使用多个匹配组。例子:
'A2=((\d{4},?)+)'
此正则表达式将匹配一个或多个由四个数字组成的序列,后跟零个或一个逗号。要使用此正则表达式,您可以REGEXP_REPLACE
改用,并保留所需的部分,同时删除其他所有内容。但是,这种方法似乎使事情变得复杂而不是简化。
最后,由于数组中值的数量可能会发生变化,我建议使用SAFE_OFFSET
来访问数组值,因为只要出现索引超出范围错误,这将返回空值。
您可以使用以下 SQL 查询作为参考:
SELECT
A1,
IF(A2[SAFE_OFFSET(0)] = A1, NULL, A2[SAFE_OFFSET(0)]) AS A2,
IF(A2[SAFE_OFFSET(1)] = A1, NULL, A2[SAFE_OFFSET(1)]) AS A2_V1,
IF(A2[SAFE_OFFSET(2)] = A1, NULL, A2[SAFE_OFFSET(2)]) AS A2_v2,
IF(A2[SAFE_OFFSET(3)] = A1, NULL, A2[SAFE_OFFSET(3)]) AS A2_v3
FROM (
SELECT
REGEXP_EXTRACT(Sample_Data, r'A1=(\d{4})') as A1,
SPLIT(REGEXP_EXTRACT(Sample_Data, r'A2=([\d,]*)'), ",") AS A2
FROM
(
SELECT 'BBBB;DDDD;CCCC;FFFF;A1=2345;A2=8907,1234,4567,2345;WWWW;GGGG' AS Sample_Data
UNION ALL
SELECT 'CCCC;EEEE;A1=6789;TTTT' AS Sample_Data)
)
推荐阅读
- javascript - 回调函数未定义,即使它在调用 javascript 之前已被定义
- android - 验证 org.WebRTC VideoFrame 或 NV21Buffer 是否包含有效(未损坏)图片
- android - Android RecyclerView 显示项目的最佳实践
- python - 如何在python中的不同变量中存储不同的值?
- flutter - 检查小部件是否在屏幕上
- r - 如何启用禁用基于 R 闪亮中一行中的字符串的操作按钮?
- python - python - 如何检查IP地址是否属于IP子网列表
- oracle - 无法创建 ODP 连接,因为 Visual Studio 不断将用户名中的第一个字母转换为大写
- javascript - 从以下 JSON 对象作为两个单独的数组获取数据的最有效方法是什么?
- html - 拖动 HTML 元素时如何去除边框?