diff --git a/datafusion/functions/src/regex/regexpinstr.rs b/datafusion/functions/src/regex/regexpinstr.rs index de460c56f63c5..a8816ac7d49fb 100644 --- a/datafusion/functions/src/regex/regexpinstr.rs +++ b/datafusion/functions/src/regex/regexpinstr.rs @@ -390,17 +390,20 @@ fn get_index( }; let search_slice = &value[byte_start_offset..]; - // A subexpression, when requested, takes precedence over the N-th match. + // `n` is 1-based, `nth` is 0-based. + let nth = (n - 1) as usize; + + // A subexpression, when requested, is located within the N-th match. let match_start = if subexpr > 0 { pattern - .captures(search_slice) + .captures_iter(search_slice) + .nth(nth) .and_then(|captures| captures.get(subexpr as usize)) .map(|matched| matched.start()) } else { - // `n` is 1-based, `nth` is 0-based. pattern .find_iter(search_slice) - .nth((n - 1) as usize) + .nth(nth) .map(|matched| matched.start()) }; @@ -685,13 +688,29 @@ mod tests { } fn test_case_sensitive_regexp_instr_scalar_subexp() { - let values = ["12 abc def ghi 34"]; - let regex = ["(abc) (def) (ghi)"]; - let start = [1]; - let nth = [1]; - let flags = ["i"]; - let subexps = [2]; - let expected: Vec = vec![8]; + // The first row locates a subexpression in the only match. The rest + // locate one in the N-th match, including an N that has no match. + let values = [ + "12 abc def ghi 34", + "12 abc def ghi 34 abc def ghi 56", + "12 abc def ghi 34 abc def ghi 56", + "12 abc def ghi 34 abc def ghi 56", + "12 abc def ghi 34 abc def ghi 56", + "12 abc def ghi 34 abc def ghi 56", + ]; + let regex = [ + "(abc) (def) (ghi)", + "(abc) (def) (ghi)", + "(abc) (def) (ghi)", + "(abc) (def) (ghi)", + "(abc) (def) (ghi)", + "(abc) (def) (ghi)", + ]; + let start = [1, 1, 1, 1, 1, 18]; + let nth = [1, 2, 2, 2, 3, 1]; + let flags = ["i", "i", "i", "i", "i", "i"]; + let subexps = [2, 1, 2, 3, 1, 2]; + let expected: Vec = vec![8, 19, 23, 27, 0, 23]; izip!( values.iter(), diff --git a/datafusion/sqllogictest/test_files/regexp/regexp_instr.slt b/datafusion/sqllogictest/test_files/regexp/regexp_instr.slt index bbe9693736442..b9a8062aaa3f3 100644 --- a/datafusion/sqllogictest/test_files/regexp/regexp_instr.slt +++ b/datafusion/sqllogictest/test_files/regexp/regexp_instr.slt @@ -73,6 +73,18 @@ SELECT ---- 11 +# The subexpression is located inside the N-th match, not inside the first one. +query I +SELECT regexp_instr('12 abc def ghi 34 abc def ghi 56', '(abc) (def) (ghi)', 1, 2, 'i', 2); +---- +23 + +# There is no third match, so there is no position to report for any subexpression. +query I +SELECT regexp_instr('12 abc def ghi 34 abc def ghi 56', '(abc) (def) (ghi)', 1, 3, 'i', 1); +---- +0 + statement error DataFusion error: Arrow error: Compute error: regexp_instr\(\) requires start to be 1-based SELECT regexp_instr('123123123123', '123', 0);