Spark 中 rtrim 函数的意外结果

Unexpected result of rtrim function in Spark

我正在尝试了解我在使用 Spark sql 函数 rtrim 时遇到的问题。我试图从字符串中删除一个子字符串,但结果与我预期的不一样。当我尝试从 test_count 中删除 _count 时,我得到的是 tes 而不是 test。但是,如果我尝试从 TEST_count 中删除 _count,我会按预期得到 TEST

我的示例代码:

import spark.implicits._
import org.apache.spark.sql.functions.rtrim

case class Test(test_count: String, test1_count: String)
val df = Seq(
    Test("test_count", "TEST_count")
).toDF

df
    .withColumn("test", rtrim($"test_count", "_count"))
    .withColumn("test1", rtrim($"test1_count", "_count"))
    .withColumn("test_", rtrim($"test_count", "count"))
    .withColumn("test1_", rtrim($"test1_count", "count"))
    .show

其结果:

+----------+-----------+----+-----+-----+------+
|test_count|test1_count|test|test1|test_|test1_|
+----------+-----------+----+-----+-----+------+
|test_count| TEST_count| tes| TEST|test_| TEST_|
+----------+-----------+----+-----+-----+------+

我试图在 _count 之前添加 \,但没有成功。我找到了实现预期结果的另一种方法,但我想更好地了解 trim 在 Spark 中的工作原理。我是做错了什么还是行为确实出乎意料?

这是正确的行为。 rtrim 删除字符串右侧所有出现的指定 chars,而不是指定的字符串。因此,如果您有 test_countrtrim _count,它将删除 _co、[=19= 中的每个字符], n, t 从右边开始,直到找到一个不是其中之一的字符。这会导致删除 test 中的最后一个 t,但不会删除 s,因为 s 不在列表中。

test_count
   ^^^^^^^ all these are in [`_`, `c`, `o`, `u`, `n`, `t`]
  ^ but this isn't, so the string is trimmed until here

为了达到你想要的效果,你可以使用regexp_replace将最后一位替换为空字符串。 $ 在正则表达式中表示字符串的结尾(右侧)。如果你想用 ltrim 做一些类似的事情,你可以在正则表达式中使用 ^

df
    .withColumn("test", regexp_replace($"test_count", "_count$", ""))
    .withColumn("test1", regexp_replace($"test1_count", "_count$", ""))
    .withColumn("test_", regexp_replace($"test_count", "count$", ""))
    .withColumn("test1_", regexp_replace($"test1_count", "count$", ""))
    .show
+----------+-----------+----+-----+-----+------+
|test_count|test1_count|test|test1|test_|test1_|
+----------+-----------+----+-----+-----+------+
|test_count| TEST_count|test| TEST|test_| TEST_|
+----------+-----------+----+-----+-----+------+