Skip to content

Commit 4d43a25

Browse files
committed
Support quantified \D and \W in regex patterns.
Also added unit and integration tests, including previously missing integration tests for quantified \d and \w. Signed-off-by: Igor Peshansky <ipeshansky@nvidia.com>
1 parent 843b8a0 commit 4d43a25

3 files changed

Lines changed: 38 additions & 1 deletion

File tree

integration_tests/src/main/python/regexp_test.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,30 @@ def test_regexp_replace_word():
921921
),
922922
conf=_regexp_conf)
923923

924+
def test_regexp_quantified_digit_word():
925+
# https://github.com/NVIDIA/cudf-spark/issues/15306
926+
gen = mk_str_gen('[a-d]{1,3}[0-9]{1,3}[ _!]{0,2}[a-d]{0,3}') \
927+
.with_special_case('䤫畍킱곂⬡❽ࢅ獰᳌蛫青') \
928+
.with_special_case('a\n2\r\n3')
929+
assert_gpu_and_cpu_are_equal_collect(
930+
lambda spark: unary_op_df(spark, gen).selectExpr(
931+
'rlike(a, "\\\\d+")',
932+
'rlike(a, "\\\\w+")',
933+
'rlike(a, "\\\\D+")',
934+
'rlike(a, "\\\\W+")',
935+
'rlike(a, "[a-d]+\\\\D+[0-9]+")',
936+
'rlike(a, "\\\\D{2,3}")',
937+
'rlike(a, "\\\\W{2,3}")',
938+
'regexp_extract(a, "(\\\\d+)", 1)',
939+
'regexp_extract(a, "(\\\\D+)", 1)',
940+
'regexp_extract(a, "([a-d]+)(\\\\D+)([a-d]+)", 2)',
941+
'regexp_extract(a, "(\\\\W+)", 1)',
942+
'regexp_replace(a, "(\\\\w+)", "#")',
943+
'regexp_replace(a, "(\\\\D+)", "#")',
944+
'regexp_replace(a, "(\\\\W+)", "@")',
945+
),
946+
conf=_regexp_conf)
947+
924948
def test_predefined_character_classes():
925949
gen = mk_str_gen('[a-zA-Z]{0,2}[\r\n!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~]{0,2}[0-9]{0,2}')
926950
assert_gpu_and_cpu_are_equal_collect(

sql-plugin/src/main/scala/com/nvidia/spark/rapids/RegexParser.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -811,7 +811,7 @@ class CudfRegexTranspiler(mode: RegexMode) {
811811
private def getUnsupportedRepetitionBaseOption(e: RegexAST): Option[RegexAST] = {
812812
e match {
813813
case RegexEscaped(ch) => ch match {
814-
case 'd' | 'w' | 's' | 'S' | 'h' | 'H' | 'v' | 'V' => None
814+
case 'd' | 'D' | 'w' | 'W' | 's' | 'S' | 'h' | 'H' | 'v' | 'V' => None
815815
case _ => Some(e)
816816
}
817817
case RegexChar(a) if "$^".contains(a) =>

tests/src/test/scala/com/nvidia/spark/rapids/RegularExpressionTranspilerSuite.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,19 @@ class RegularExpressionTranspilerSuite extends AnyFunSuite {
472472
assertCpuGpuMatchesRegexpReplace(patterns, inputs)
473473
}
474474

475+
test("quantified \\D and \\W") {
476+
// see https://github.com/NVIDIA/cudf-spark/issues/15306
477+
val inputs = Seq("", "abc", "123", "a1b2", "___", "a_b 1", "!!!", "ab12cd",
478+
"a\rb", "1\r2", "1\n2", "1\r\n2", " \t\r\n")
479+
val findPatterns = Seq(raw"\D+", raw"\W+", raw"\D*", raw"\W*", raw"\D{2,3}", raw"\W{2,3}",
480+
raw"(\D+)", raw"(\W+)")
481+
// \D* and \W* omitted from replace: empty-match semantics differ (see issue 4884)
482+
val replacePatterns =
483+
Seq(raw"\D+", raw"\W+", raw"\D{2,3}", raw"\W{2,3}", raw"(\D+)", raw"(\W+)")
484+
assertCpuGpuMatchesRegexpFind(findPatterns, inputs)
485+
assertCpuGpuMatchesRegexpReplace(replacePatterns, inputs)
486+
}
487+
475488
test("dot matches CR on GPU but not on CPU") {
476489
// see https://github.com/rapidsai/cudf/issues/9619
477490
val pattern = "1."

0 commit comments

Comments
 (0)