如何在第一次出现字符串时拆分列?

时间:2018-12-03 02:54:16

标签: apache-spark apache-spark-sql

我有以下格式的数据框。我想在“。”之前将单词分开。在用户名列中,其余的保留为其他列

+----+--------+
|Name|Username|
+----+--------+
| ABC|a.b.cdef|
+----+--------+

我想将用户名拆分为

+----+--------+---+------+
|Name|Username|  A|     B|
+----+--------+---+------+
| ABC|a.b.cdef|  a|b.cdef|
+----+--------+---+------+

前缀的长度(在第一个.之前)是固定的,因此我无法使用substring标准函数。

2 个答案:

答案 0 :(得分:0)

您似乎想分割第一个.,您可以使用正则表达式环顾四周来实现。这将使您摆脱regexp_replace步骤:

(df.withColumn("Username", split($"Username", "(?<=^[^.]*)\\."))
   .withColumn("A", $"Username"(0))
   .withColumn("B", $"Username"(1))).show

+----+-----------+---+------+
|Name|   Username|  A|     B|
+----+-----------+---+------+
| ABC|[a, b.cdef]|  a|b.cdef|
+----+-----------+---+------+

模式(?<=^[^.]*)\\.的详细信息:

  • 使用?<=后的外观限制.分裂;
  • ^[^.]*从字符串的开头匹配一个不包含.的模式。请注意,第一个^表示字符串的开头。 [^.]是与.以外的任何字符匹配的字符类,而*是表示零个或多个的量词。

组合在一起的模式与字符串中的第一个.相匹配。

答案 1 :(得分:0)

对于这种特殊情况,我会(重新)考虑一个用户定义的函数(并避免使用正则表达式,因为可能在几周后可能难以理解)。

val splitFirst = udf { (s: String) => s.split("\\.", 2) }

scala> data.withColumn("AB", splitFirst($"username")).show
+----+--------+-----------+
|Name|Username|         AB|
+----+--------+-----------+
| ABC|a.b.cdef|[a, b.cdef]|
+----+--------+-----------+

val solution = data
  .withColumn("AB", splitFirst($"username"))
  .withColumn("A", $"AB"(0))
  .withColumn("B", $"AB"(1))
scala> solution.show
+----+--------+-----------+---+------+
|Name|Username|         AB|  A|     B|
+----+--------+-----------+---+------+
| ABC|a.b.cdef|[a, b.cdef]|  a|b.cdef|
+----+--------+-----------+---+------+

诀窍是使用适当的String.split

  

公共字符串[]拆分(字符串正则表达式,整数限制)将该字符串拆分为给定正则表达式的匹配项。

     

limit参数控制应用图案的次数,因此会影响结果数组的长度。

     

如果限制为正,则模式将最多应用限制-1次,数组的长度将不超过限制,并且数组的最后一个条目将包含除最后匹配的定界符之外的所有输入。