PySpark SQL特殊字符分隔符拆分列失败及split函数列参数调用疑问
问题:PySpark SQL按列存储的特殊字符分隔符拆分失效及API调用疑问
尝试用PySpark SQL按另一列存储的字符作为分隔符拆分目标列,但$、^等特殊字符无法正常工作。测试代码如下:
df = spark.createDataFrame([("50000.0#0#0#", "#"), ("0@1000.0@", "@"), ("1$", "$"), ("1000.00^Test_string", "^")],["VALUES", "Delimiter"]) df.registerTempTable("cleanTable") df2 = spark.sql(""" SELECT VALUES, cast(Delimiter as string), split(cast(VALUES as string), cast(Delimiter as string)) as split_values FROM cleanTable """)
执行结果:
+-------------------+---------+---------------------+ |VALUES |Delimiter|split_values | +-------------------+---------+---------------------+ |50000.0#0#0# |# |[50000.0, 0, 0, ] | |0@1000.0@ |@ |[0, 1000.0, ] | |1$ |$ |[1$, ] | |1000.00^Test_string|^ |[1000.00^Test_string]| +-------------------+---------+---------------------+
疑问:
- 为何$、^这类分隔符无法生效,是否需要额外配置?
- 除PySpark SQL方式外,是否支持
split(col('a'),col('b'))这种以列作为参数的调用方式?
解答
1. 特殊字符分隔符失效的原因及解决办法
PySpark的split函数第二个参数是正则表达式,而$、^属于正则元字符:
$表示匹配行尾位置^表示匹配行首位置
这些字符不会被当作普通分隔符处理,导致拆分失败。
解决办法是把分隔符转义为正则字面量,有两种常用方式:
方式一:用\\Q和\\E包裹分隔符
\\Q和\\E在正则中表示字面量区间,中间的所有字符都会被当作普通字符解析。修改SQL如下:
SELECT VALUES, Delimiter, split(VALUES, concat('\\Q', Delimiter, '\\E')) as split_values FROM cleanTable
方式二:手动转义正则元字符
用regexp_replace将分隔符中的正则特殊字符(如$、^、.、*等)添加转义符\:
SELECT VALUES, Delimiter, split(VALUES, regexp_replace(Delimiter, '([\\$\\^\\\\.+*?\\[\\](){}|\\-])', '\\\\$1')) as split_values FROM cleanTable
修改后执行结果会正常拆分所有分隔符:
+-------------------+---------+-----------------------+ |VALUES |Delimiter|split_values | +-------------------+---------+-----------------------+ |50000.0#0#0# |# |[50000.0, 0, 0, ] | |0@1000.0@ |@ |[0, 1000.0, ] | |1$ |$ |[1, ] | |1000.00^Test_string|^ |[1000.00, Test_string] | +-------------------+---------+-----------------------+
2. DataFrame API是否支持split(col('a'), col('b'))
- Spark 3.0及以上版本:支持该调用方式,
split函数的第二个参数可以是列表达式。同样需要对分隔符列做正则转义处理,示例代码:
from pyspark.sql import functions as F df3 = df.withColumn( "split_values", F.split(F.col("VALUES"), F.concat(F.lit("\\Q"), F.col("Delimiter"), F.lit("\\E"))) ) df3.show(truncate=False)
- Spark 2.x及更早版本:不支持第二个参数为列,仅能传入字符串常量。此时可以通过
expr函数嵌入SQL表达式实现类似效果:
from pyspark.sql import functions as F df3 = df.withColumn( "split_values", F.expr("split(VALUES, concat('\\Q', Delimiter, '\\E'))") ) df3.show(truncate=False)
内容的提问来源于stack exchange,提问作者Sr Jefers
相关产品推荐
相关产品推荐

