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_count
和 rtrim
_count
,它将删除 _
、c
、o
、[=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_|
+----------+-----------+----+-----+-----+------+
我正在尝试了解我在使用 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_count
和 rtrim
_count
,它将删除 _
、c
、o
、[=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_|
+----------+-----------+----+-----+-----+------+