PySpark正则提取ml前数字:从产品字段提取容量的问题
解决PySpark DataFrame中提取容量信息的正则表达式问题
原始DataFrame定义
from pyspark.sql.functions import * from pyspark.sql.types import * data = [ ('1',"12345 soda bottle 1500ml"), ('2',"6789 beer can 450ml"), ("3","beer with no number before 375ml") ] columnname = ['id','product'] df = spark.createDataFrame(data=data, schema=columnname)
原始数据展示
+---+--------------------------------+ |id |product | +---+--------------------------------+ |1 |12345 soda bottle 1500ml | |2 |6789 beer can 450ml | |3 |beer with no number before 375ml| +---+--------------------------------+
需求说明
新增volume和volume_number列,从product字段中提取容量信息:
volume:提取完整的容量格式(如1500ml)volume_number:提取容量数值(如1500)
需避开字段中无关数字的干扰。
尝试的代码及错误结果
尝试的代码:
df = df.withColumn('volume',regexp_extract(col('product'), '([0-9]{3,5}.*ml)', 1) ).withColumn('volume_number',regexp_extract(col('volume'), '^[^m]+', 0))
错误结果:
+---+--------------------------------+------------------------+----------------------+ |id |product |volume |volume_number | +---+--------------------------------+------------------------+----------------------+ |1 |12345 soda bottle 1500ml |12345 soda bottle 1500ml|12345 soda bottle 1500| |2 |6789 beer can 450ml |6789 beer can 450ml |6789 beer can 450 | |3 |beer with no number before 375ml|375ml |375 | +---+--------------------------------+------------------------+----------------------+
期望输出
+---+--------------------------------+------------------------+----------------------+ |id |product |volume |volume_number | +---+--------------------------------+------------------------+----------------------+ |1 |12345 soda bottle 1500ml |1500ml |1500 | |2 |6789 beer can 450ml |450ml |450 | |3 |beer with no number before 375ml|375ml |375 | +---+--------------------------------+------------------------+----------------------+
正确解决方案
原正则表达式([0-9]{3,5}.*ml)的问题在于:它会匹配从第一个3-5位数字开始到ml的所有内容,导致包含了无关的前置文本和数字。
正确代码
df = df.withColumn('volume', regexp_extract(col('product'), r'(\d+ml)', 1)) \ .withColumn('volume_number', regexp_extract(col('product'), r'(\d+)(?=ml)', 1))
正则说明
r'(\d+ml)':匹配**一个或多个数字紧跟ml**的内容,只提取带ml的容量单元,自动避开前面无ml后缀的无关数字。r'(\d+)(?=ml)':使用正向预查(?=ml),匹配后面紧跟ml的数字,直接提取容量数值,无需依赖volume列,更高效。
运行上述代码后,将得到与期望完全一致的输出。
内容的提问来源于stack exchange,提问作者bzimons
相关产品推荐
相关产品推荐

