【问题标题】:How do I replace a delimiter that appears only in between something?如何替换仅出现在某些内容之间的分隔符?
【发布时间】:2020-07-29 04:36:19
【问题描述】:

我对此数据有一个用例:

1. "apple+case"
2. "apple+case+10+cover"
3. "apple+case+10++cover"
4. "+apple"
5. "iphone8+"

目前,我这样做是为了将 + 替换为空格,如下所示:

def normalizer(value: String): String = {
    if (value == null) {
      null
    } else {
       value.replaceAll("\\+", BLANK_SPACE)        
     }
  }

  val testUDF = udf(normalizer(_: String): String)

  df.withColumn("newCol",  testUDF($"value"))

但这是替换所有“+”。如何替换字符串之间的“+”,同时处理以下用例:“apple+case+10++cover”=>“apple case 10+ cover”?

The output should be
1. "apple case"
2. "apple case 10 cover"
3. "apple case 10+ cover"
4. "apple"
5. "iphone8+"

【问题讨论】:

    标签: regex scala apache-spark regex-lookarounds regexp-replace


    【解决方案1】:

    您可以使用regexp_replace 来代替udf,它应该更快。在大多数情况下,您可以在正则表达式中使用负前瞻,但对于“+apple”,您实际上希望将“+”替换为“”(而不是空格)。最简单的方法是简单地使用正则表达式。

    df.withColumn("newCol", regexp_replace($"value", "^\\+", ""))
      .withColumn("newCol", regexp_replace($"newCol", "\\+(?!\\+|$)", " "))
    

    这将给出:

    +--------------------+--------------------+
    |value               |newCol              |
    +--------------------+--------------------+
    |apple+case          |apple case          |
    |apple+case+10+cover |apple case 10 cover |
    |apple+case+10++cover|apple case 10+ cover|
    |+apple              |apple               |
    |iphone8+            |iphone8+            |
    +--------------------+--------------------+
    

    为了使其更加模块化和可重用,您可以将其定义为函数:

    def normalizer(c: String) = regexp_replace(regexp_replace(col(c), "^\\+", ""), "\\+(?!\\+|$)", " ")
    
    df.withColumn("newCol", normalizer("value"))
    

    【讨论】:

    • 问题是我需要在多个 DF 中应用它,这就是为什么认为 UDF 是更清洁的方法。如果您有任何其他更清洁、更快的方法,请告诉我,我可以在多个 DF 中应用这种方法
    • @user3407267:如果您愿意,您可以简单地将正则表达式放入您的 UDF 中,它应该仍然可以工作。但是您也可以在方法中使用regexp_replace(保持速度),我在答案中添加了一些信息。
    【解决方案2】:

    您可以尝试进行两个正则表达式替换:

    df.withColumn("newCol", regexp_replace(
        regexp_replace(testUDF("value"), "(?<=\d)\+(?!\+)", "+ "),
        "(?<!\d)\+", " ")).show
    

    内部正则表达式替换将针对单个加号前面有数字的边缘情况,应通过添加空格(但不删除加号)来替换。示例:

    apple+case+10+cover  -->  apple+case+10+ cover
    

    然后,外部正则表达式替换针对所有前面没有数字的加号,并用空格替换它们。示例,从上面继续:

    apple+case+10+ cover -->  apple case 10+ cover
    

    【讨论】:

    • 这不会取代 "apple+case+10+cover" 和 "apple+case+10++cover" - 通过regex101.com 测试这似乎只适用于单个 "+"
    • 我认为apple+case+10+cover 是错误数据。你真的有这些数据吗?
    • 是的。它是常见的用例之一。至少我希望 ++ 替换为单个“”(最坏情况的解决方案)
    • testUDF("value") 应该已经替换了字符串中的所有 + 对吗?应该在外面吗?
    • @user3407267 请检查更新的答案,它现在应该可以工作了。
    猜你喜欢
    • 2020-10-30
    • 2013-07-24
    • 1970-01-01
    • 2017-08-30
    • 1970-01-01
    • 1970-01-01
    • 2012-06-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多