PySpark中如何原生提取正则表达式的多匹配结果?
实现PySpark原生正则多匹配分组的数组提取
首先得明确:PySpark确实没有提供直接返回所有正则匹配分组列表的原生函数(比如类似Python re.findall的功能),但我们可以通过组合几个原生函数来实现这个需求,完全不需要写基于re.findall的UDF。
针对你的场景(正则只有一个分组,需要获取所有匹配的分组值组成数组),可以按以下步骤操作:
步骤1:收集所有匹配的分组值并转成数组
我们可以利用regexp_replace把每个匹配的分组值用一个特殊分隔符拼接起来,再用split转成数组,最后过滤掉可能的空元素:
from pyspark.sql import SparkSession from pyspark.sql import functions as F # 初始化SparkSession spark = SparkSession.builder.appName("RegexMatches").getOrCreate() # 测试数据 df = spark.createDataFrame([("2 AVENUE DES LAPINOUS",)], ["col_name"]) # 定义正则(你的场景是单分组:(\w+)) my_regex = r"(\w+)" # 用不可见分隔符\u0001避免和原字符串内容冲突 separator = r"\u0001" # 1. 用regexp_replace把所有匹配的分组值用分隔符拼接 # 2. split转成数组 # 3. filter过滤掉最后可能的空元素(因为最后一个匹配后也会加分隔符) df = df.withColumn( "matches_array", F.expr(f"filter(split(regexp_replace(col_name, '{my_regex}', r'$1{separator}'), '{separator}'), x -> x != '')") )
执行后,matches_array列的值就是["2", "AVENUE", "DES", "LAPINOUS"],完全符合你要的所有匹配分组的列表。
步骤2:操作数组中的元素
得到数组后,你就可以像操作普通PySpark数组一样访问元素了,比如实现你示例里的$1[0] - $1[1]逻辑(注意你示例里的$2应该是笔误,因为你的正则只有一个分组):
df = df.withColumn( "result", F.concat( F.col("matches_array")[0], F.lit(" - "), F.col("matches_array")[1] ) ) # 查看结果 df.select("col_name", "matches_array", "result").show(truncate=False)
输出结果:
+------------------------+------------------------------+-------------+ |col_name |matches_array |result | +------------------------+------------------------------+-------------+ |2 AVENUE DES LAPINOUS |[2, AVENUE, DES, LAPINOUS] |2 - AVENUE | +------------------------+------------------------------+-------------+
扩展:多分组的情况(可选)
如果你的正则有多个分组,比如(\d+) (\w+),想要收集每个匹配的多分组值,可以用不同的分隔符区分分组和匹配,比如用;分隔每个匹配项,用|分隔分组:
multi_regex = r"(\d+) (\w+)" df_multi = spark.createDataFrame([("2 AVENUE 3 STREET",)], ["col_name"]) df_multi = df_multi.withColumn( "matches_struct", F.expr(""" transform( filter(split(regexp_replace(col_name, '{multi_regex}', r'$1|$2;'), ';'), x -> x != ''), x -> struct(split(x, '|')[0] as num, split(x, '|')[1] as word) ) """) )
这样就能得到一个结构体数组,每个元素包含匹配的两个分组值。
关键说明
- 选择分隔符时,尽量用原字符串中不会出现的字符(比如
\u0001这种不可见控制字符),避免拆分时出错。 - 整个流程完全使用PySpark原生函数,不需要依赖Python的
re库,性能比UDF更优,尤其是大数据量场景。
内容的提问来源于stack exchange,提问作者Amesys
相关产品推荐
相关产品推荐

