使用 pyspark 使用 regexp_extract 解析字符串

问题描述

我正在尝试使用正则表达式将字符串拆分为不同的列

下面是我的数据

decodeData = [('M|C705|Exx05','2'),('M|Exx05','4'),('M|C705 P|Exx05','6'),('M|C705 P|8960 L|Exx05','7'),('M|C705 P|78|8960','9')]

df = sc.parallelize(decodeData).toDF(['Decode',''])

dfNew = df.withColumn('Exx05',regexp_extract(col('Decode'),'(M|P|M)(\\|Exx05)',1)).withColumn('C705','(M|P|M)(\\|C705)',1)) .withColumn('8960','(M|P|M)(\\|8960)',1))
dfNew.show()

Result
+--------------------+---+-----+----+-----+
|              Decode|   |Exx05|C705| 8960|
+--------------------+---+-----+----+-----+
|        M|C705|Exx05 | 2  |     |   M|    |
|             M|Exx05 | 4  |    M|    |    |
|      M|C705 P|Exx05 | 6  |    P|   M|    |
|M|C705 P|8960 L|Exx05| 7  |    M|   M|   P|
|    M|C705 P|78|8960 | 9  |     |   M|    |
+--------------------+---+-----+----+-----+

这里我试图提取字符串 Exx05,C705,8960代码,这可能属于 M/P/L 代码 例如:在解码 'M|C705 P|8960 L|Exx05' 时,我希望在相应列中的结果为 L M P。但是我在这里遗漏了一些逻辑,我发现很难破解

预期结果

  +--------------------+---+-----+----+-----+
    |              Decode|   |Exx05|C705| 8960|
    +--------------------+---+-----+----+-----+
    |        M|C705|Exx05 |   |    M|   M|    |
    |             M|Exx05 |   |    M|    |    |
    |      M|C705 P|Exx05 |   |    P|   M|    |
    |M|C705 P|8960 L|Exx05|   |    L|   M|   P|
    |    M|C705 P|78|8960 |   |     |   M|   P|
    +--------------------+---+-----+----+-----+

当我尝试相应地更改 reg 表达式时,它适用于某些情况而不适用于其他示例情况,这只是我正在处理的实际数据的一个子集。

eg: 1. Exx05 可以落入任何代码 M/L/P 甚至可以落入任何位置,开始,中间,结束等

  1. 一个解码器只能属于每个条目/ID 的 1 个(M 或 L 或 P)代码,即 M|Exx05 P|8960 L|Exx05 - 这里是 Exx05在 M 和 L 中,这种情况将不存在。

解决方法

您可以在正则表达式中添加 ([^ ])* 以扩展它,使其匹配任何不以空格分隔的连续模式:

dfNew = df.withColumn(
    'Exx05',regexp_extract(col('Decode'),'(M|P|L)([^ ])*(\\|Exx05)',1)
).withColumn(
    'C705','(M|P|L)([^ ])*(\\|C705)',1)
).withColumn(
    '8960','(M|P|L)([^ ])*(\\|8960)',1)
)

dfNew.show(truncate=False)
+---------------------+---+-----+----+----+
|Decode               |   |Exx05|C705|8960|
+---------------------+---+-----+----+----+
|M|C705|Exx05         |2  |M    |M   |    |
|M|Exx05              |4  |M    |    |    |
|M|C705 P|Exx05       |6  |P    |M   |    |
|M|C705 P|8960 L|Exx05|7  |L    |M   |P   |
|M|C705$P|78|8960     |9  |     |M   |P   |
+---------------------+---+-----+----+----+
,

我们使用 X(?=Y) 也称为 lookahead assertion 怎么样。这确保我们只匹配 X 后跟 Y

from pyspark.sql.functions import*
dfNew = df.withColumn('Exx05','([A-Z](?=\|Exx05))',1)).withColumn('C705','([A-Z](?=\|C705))',1)) .withColumn('8960','([A-Z]+(?=\|[0-9]|8960))',1))
dfNew.show()

+--------------------+---+-----+----+----+
|              Decode|  t|Exx05|C705|8960|
+--------------------+---+-----+----+----+
|        M|C705|Exx05|  2|     |   M|    |
|             M|Exx05|  4|    M|    |    |
|      M|C705 P|Exx05|  6|    P|   M|    |
|M|C705 P|8960 L|E...|  7|    L|   M|   P|
|    M|C705 P|78|8960|  9|     |   M|   P|
+--------------------+---+-----+----+----+