ClickHouse/docs/zh/sql-reference/functions/string-search-functions.md
2024-04-01 17:59:38 +02:00

26 KiB
Raw Blame History

slug
/zh/sql-reference/functions/string-search-functions

字符串搜索函数

本节中的所有函数默认情况下都区分大小写进行搜索。不区分大小写的搜索通常由单独的函数变体提供。
请注意,不区分大小写的搜索,遵循英语的小写-大写规则。 例如。英语中大写的iI,而在土耳其语中则是İ, 对于英语以外的语言,结果可能会不符合预期。

本节中的函数还假设搜索字符串和被搜索字符串是单字节编码文本(例如ASCII)。如果违反此假设不会抛出异常且结果为undefined。
UTF-8 编码字符串的搜索通常由单独的函数变体提供。同样,如果使用 UTF-8 函数变体但输入字符串不是 UTF-8 编码文本,不会抛出异常且结果为 undefined。 需要注意,函数不会执行自动 Unicode 规范化,您可以使用normalizeUTF8*() 函数来执行此操作。 在字符串函数字符串替换函数 会分别说明.

position

返回字符串haystack中子字符串needle的位置(以字节为单位,从 1 开始)。

语法

position(haystack, needle[, start_pos])

别名:

  • position(needle IN haystack)

参数

  • haystack — 被检索查询字符串,类型为String.
  • needle — 进行查询的子字符串,类型为String.
  • start_pos 在字符串haystack 中开始检索的位置(从1开始),类型为UInt,可选。

返回值

  • 若子字符串存在,返回位置(以字节为单位,从 1 开始)。
  • 如果不存在子字符串,返回 0。

如果子字符串 needle 为空,则:

  • 如果未指定 start_pos,返回 1
  • 如果 start_pos = 0,则返回 1
  • 如果 start_pos >= 1start_pos <= length(haystack) + 1,则返回 start_pos
  • 否则返回 0

以上规则同样在这些函数中生效: locate, positionCaseInsensitive, positionUTF8, positionCaseInsensitiveUTF8

数据类型: Integer.

示例

SELECT position('Hello, world!', '!');

结果:

┌─position('Hello, world!', '!')─┐
│                             13 │
└────────────────────────────────┘

示例,使用参数 start_pos :

SELECT
    position('Hello, world!', 'o', 1),
    position('Hello, world!', 'o', 7)

结果:

┌─position('Hello, world!', 'o', 1)─┬─position('Hello, world!', 'o', 7)─┐
│                                 5 │                                 9 │
└───────────────────────────────────┴───────────────────────────────────┘

示例,needle IN haystack:

SELECT 6 = position('/' IN s) FROM (SELECT 'Hello/World' AS s);

结果:

┌─equals(6, position(s, '/'))─┐
│                           1 │
└─────────────────────────────┘

示例,子字符串 needle 为空:

SELECT
    position('abc', ''),
    position('abc', '', 0),
    position('abc', '', 1),
    position('abc', '', 2),
    position('abc', '', 3),
    position('abc', '', 4),
    position('abc', '', 5)

结果:

┌─position('abc', '')─┬─position('abc', '', 0)─┬─position('abc', '', 1)─┬─position('abc', '', 2)─┬─position('abc', '', 3)─┬─position('abc', '', 4)─┬─position('abc', '', 5)─┐
│                   1 │                      1 │                      1 │                      2 │                      3 │                      4 │                      0 │
└─────────────────────┴────────────────────────┴────────────────────────┴────────────────────────┴────────────────────────┴────────────────────────┴────────────────────────┘

locate

类似于 position 但交换了 haystacklocate 参数。

此函数的行为取决于 ClickHouse 版本:

  • 在 v24.3 以下的版本中,locate 是函数position的别名,参数为 (haystack, needle[, start_pos])
  • 在 v24.3 及以上的版本中,, locate 是独立的函数 (以更好地兼容 MySQL) ,参数为 (needle, haystack[, start_pos])。 之前的行为 可以在设置中恢复 function_locate_has_mysql_compatible_argument_order = false;

语法

locate(needle, haystack[, start_pos])

positionCaseInsensitive

类似于 position 但是不区分大小写。

positionUTF8

类似于 position 但是假定 haystackneedle 是 UTF-8 编码的字符串。

示例

函数 positionUTF8 可以正确的将字符 ö 计为单个 Unicode 代码点(ö由两个点表示):

SELECT positionUTF8('Motörhead', 'r');

结果:

┌─position('Motörhead', 'r')─┐
│                          5 │
└────────────────────────────┘

positionCaseInsensitiveUTF8

类似于 positionUTF8 但是不区分大小写。

multiSearchAllPositions

类似于 position 但是返回多个在字符串 haystackneedle 子字符串的位置的数组(以字节为单位,从 1 开始)。

:::note 所有以 multiSearch*() 开头的函数仅支持最多 28needle. :::

语法

multiSearchAllPositions(haystack, [needle1, needle2, ..., needleN])

参数

  • haystack — 被检索查询字符串,类型为String.
  • needle — 子字符串数组, 类型为Array

返回值

  • 位置数组,数组中的每个元素对应于 needle 数组中的一个元素。如果在 haystack 中找到子字符串,则返回的数组中的元素为子字符串的位置(以字节为单位,从 1 开始);如果未找到子字符串,则返回的数组中的元素为 0。

示例

SELECT multiSearchAllPositions('Hello, World!', ['hello', '!', 'world']);

结果:

┌─multiSearchAllPositions('Hello, World!', ['hello', '!', 'world'])─┐
│ [0,13,0]                                                          │
└───────────────────────────────────────────────────────────────────┘

multiSearchAllPositionsUTF8

类似于 multiSearchAllPositions ,但假定 haystackneedle-s 是 UTF-8 编码的字符串。

multiSearchFirstPosition

类似于 position , 在字符串haystack中匹配多个needle子字符串,从左开始任一匹配的子串,返回其位置。

函数 multiSearchFirstPositionCaseInsensitive, multiSearchFirstPositionUTF8multiSearchFirstPositionCaseInsensitiveUTF8 提供此函数的不区分大小写 以及/或 UTF-8 变体。

语法

multiSearchFirstPosition(haystack, [needle1, needle2, , needleN])

multiSearchFirstIndex

在字符串haystack中匹配最左侧的 needlei 子字符串,返回其索引 i (从1开始)如无法匹配则返回0。

函数 multiSearchFirstIndexCaseInsensitive, multiSearchFirstIndexUTF8multiSearchFirstIndexCaseInsensitiveUTF8 提供此函数的不区分大小写以及/或 UTF-8 变体。

语法

multiSearchFirstIndex(haystack, \[needle<sub>1</sub>, needle<sub>2</sub>, , needle<sub>n</sub>\])

multiSearchAny

至少已有一个子字符串needle匹配 haystack 时返回1否则返回 0 。

函数 multiSearchAnyCaseInsensitive, multiSearchAnyUTF8multiSearchAnyCaseInsensitiveUTF8 提供此函数的不区分大小写以及/或 UTF-8 变体。

语法

multiSearchAny(haystack, [needle1, needle2, , needleN])

match

返回字符串 haystack 是否匹配正则表达式 pattern re2正则语法参考

匹配基于 UTF-8例如. 匹配 Unicode 代码点 ¥,它使用两个字节以 UTF-8 表示。T正则表达式不得包含空字节。如果 haystackpattern不是有效的 UTF-8则此行为为undefined。 与 re2 的默认行为不同,. 会匹配换行符。要禁用此功能,请在模式前面添加(?-s)

如果仅希望搜索子字符串,可以使用函数 likeposition 来替代,这些函数的性能比此函数更高。

语法

match(haystack, pattern)

别名: haystack REGEXP pattern operator

multiMatchAny

类似于 match,如果至少有一个表达式 pattern<sub>i</sub> 匹配字符串 haystack则返回1否则返回0。

:::note multi[Fuzzy]Match*() 函数家族使用了(Vectorscan)[https://github.com/VectorCamp/vectorscan]库. 因此,只有当 ClickHouse 编译时支持矢量扫描时,它们才会启用。

要关闭所有使用矢量扫描(hyperscan)的功能,请使用设置 SET allow_hyperscan = 0;

由于Vectorscan的限制haystack 字符串的长度必须小于232字节。

Hyperscan 通常容易受到正则表达式拒绝服务 (ReDoS) 攻击。有关更多信息,请参见 https://www.usenix.org/conference/usenixsecurity22/presentation/turonova
https://doi.org/10.1007/s10664-021-10033-1
https://doi.org/10.1145/3236024.3236027
建议用户谨慎检查提供的表达式。

:::

如果仅希望搜索子字符串,可以使用函数 multiSearchAny 来替代,这些函数的性能比此函数更高。

语法

multiMatchAny(haystack, \[pattern<sub>1</sub>, pattern<sub>2</sub>, , pattern<sub>n</sub>\])

multiMatchAnyIndex

类似于 multiMatchAny ,返回任何子串匹配 haystack 的索引。

语法

multiMatchAnyIndex(haystack, \[pattern<sub>1</sub>, pattern<sub>2</sub>, , pattern<sub>n</sub>\])

multiMatchAllIndices

类似于 multiMatchAny,返回一个数组,包含所有匹配 haystack 的子字符串的索引。

语法

multiMatchAllIndices(haystack, \[pattern<sub>1</sub>, pattern<sub>2</sub>, , pattern<sub>n</sub>\])

multiFuzzyMatchAny

类似于 multiMatchAny ,如果任一 pattern 匹配 haystack则返回1 within a constant edit distance. 该功能依赖于实验特征 hyperscan 库,并且对于某些边缘场景可能会很慢。性能取决于编辑距离distance的值和使用的partten,但与非模糊搜索相比,它的开销总是更高的。

:::note 由于 hyperscan 的限制,multiFuzzyMatch*() 函数族不支持 UTF-8 正则表达式hyperscan以一串字节来处理。 :::

语法

multiFuzzyMatchAny(haystack, distance, \[pattern<sub>1</sub>, pattern<sub>2</sub>, , pattern<sub>n</sub>\])

multiFuzzyMatchAnyIndex

类似于 multiFuzzyMatchAny 返回在编辑距离内与haystack匹配的任何索引

语法

multiFuzzyMatchAnyIndex(haystack, distance, \[pattern<sub>1</sub>, pattern<sub>2</sub>, , pattern<sub>n</sub>\])

multiFuzzyMatchAllIndices

类似于 multiFuzzyMatchAny 返回在编辑距离内与haystack匹配的所有索引的数组。

语法

multiFuzzyMatchAllIndices(haystack, distance, \[pattern<sub>1</sub>, pattern<sub>2</sub>, , pattern<sub>n</sub>\])

extract

使用正则表达式提取字符串。如果字符串 haystack 不匹配正则表达式 pattern ,则返回空字符串。

对于没有子模式的正则表达式,该函数使用与整个正则表达式匹配的片段。否则,它使用与第一个子模式匹配的片段。

语法

extract(haystack, pattern)

extractAll

使用正则表达式提取字符串的所有片段。如果字符串 haystack 不匹配正则表达式 pattern ,则返回空字符串。

返回所有匹配项组成的字符串数组。

子模式的行为与函数extract中的行为相同。

语法

extractAll(haystack, pattern)

extractAllGroupsHorizontal

使用pattern正则表达式匹配haystack字符串的所有组。

返回一个元素为数组的数组,其中第一个数组包含与第一组匹配的所有片段,第二个数组包含与第二组匹配的所有片段,依此类推。

这个函数相比 extractAllGroupsVertical更慢。

语法

extractAllGroupsHorizontal(haystack, pattern)

参数

  • haystack — 输入的字符串,数据类型为String.
  • pattern — 正则表达式(re2正则语法参考 ,必须包含 group每个 group 用括号括起来。 如果 pattern 不包含 group 则会抛出异常。 数据类型为String.

返回值

如果haystack不匹配pattern正则表达式,则返回一个空数组的数组。

示例

SELECT extractAllGroupsHorizontal('abc=111, def=222, ghi=333', '("[^"]+"|\\w+)=("[^"]+"|\\w+)');

结果:

┌─extractAllGroupsHorizontal('abc=111, def=222, ghi=333', '("[^"]+"|\\w+)=("[^"]+"|\\w+)')─┐
│ [['abc','def','ghi'],['111','222','333']]                                                │
└──────────────────────────────────────────────────────────────────────────────────────────┘

extractAllGroupsVertical

使用正则表达式 pattern匹配字符串haystack中的所有group。返回一个数组其中每个数组包含每个group的匹配片段。片段按照在haystack中出现的顺序进行分组。

语法

extractAllGroupsVertical(haystack, pattern)

参数

  • haystack — 输入的字符串,数据类型为String.
  • pattern — 正则表达式(re2正则语法参考 必须包含group每个group用括号括起来。 如果 pattern 不包含group则会抛出异常。 数据类型为String.

返回值

如果haystack不匹配pattern正则表达式,则返回一个空数组。

示例

SELECT extractAllGroupsVertical('abc=111, def=222, ghi=333', '("[^"]+"|\\w+)=("[^"]+"|\\w+)');

结果:

┌─extractAllGroupsVertical('abc=111, def=222, ghi=333', '("[^"]+"|\\w+)=("[^"]+"|\\w+)')─┐
│ [['abc','111'],['def','222'],['ghi','333']]                                            │
└────────────────────────────────────────────────────────────────────────────────────────┘

like

返回字符串 haystack 是否匹配 LIKE 表达式 pattern

一个 LIKE 表达式可以包含普通字符和以下元字符:

  • % 表示任意数量的任意字符(包括零个字符)。
  • _ 表示单个任意字符。
  • \ 用于转义文字 %, _\

匹配基于 UTF-8例如 _ 匹配 Unicode 代码点 ¥,它使用两个字节以 UTF-8 表示。

如果 haystackLIKE 表达式不是有效的 UTF-8则行为是未定义的。

不会自动执行 Unicode 规范化,您可以使用normalizeUTF8*() 函数来执行此操作。

如果需要匹配字符 %, _/(这些是 LIKE 元字符),请在其前面加上反斜杠:\%, \_\\。 如果在非 %, _\ 字符前使用反斜杠,则反斜杠将失去其特殊含义(即被解释为字面值)。 请注意ClickHouse 要求字符串中使用反斜杠 也需要被转义, 因此您实际上需要编写 \\%\\_\\\\

对于形式为 %needle% 的 LIKE 表达式,函数的性能与 position 函数相同。 所有其他 LIKE 表达式都会被内部转换为正则表达式,并以与函数 match 相似的性能执行。

语法

like(haystack, pattern)

别名: haystack LIKE pattern (operator)

notLike

类似于 like 但是返回相反的结果。

别名: haystack NOT LIKE pattern (operator)

ilike

类似于 like 但是不区分大小写。

别名: haystack ILIKE pattern (operator)

notILike

类似于 ilike 但是返回相反的结果。

别名: haystack NOT ILIKE pattern (operator)

ngramDistance

计算字符串 haystack 和子字符串 needle 的 4-gram 距离。 为此,它计算两个 4-gram 多重集之间的对称差异,并通过它们的基数之和对其进行标准化。返回 0 到 1 之间的 Float32 浮点数。返回值越小,代表字符串越相似. 如果参数 needle or haystack 是常数且大小超过 32Kb则抛出异常。如果参数 haystackneedle 是非常数且大小超过 32Kb ,则返回值恒为 1。

函数 ngramDistanceCaseInsensitive, ngramDistanceUTF8, ngramDistanceCaseInsensitiveUTF8 提供此函数的不区分大小写以及/或 UTF-8 变体。

语法

ngramDistance(haystack, needle)

ngramSearch

类似于ngramDistance,但计算needle字符串和 haystack 字符串之间的非对称差异,即来自 needle 的 n-gram 数量减去由needle数量归一化的 n-gram 的公共数量 n-gram。返回 0 到 1 之间的 Float32 浮点数。结果越大,needle 越有可能在 haystack 中。该函数对于模糊字符串搜索很有用。另请参阅函数 `soundex``。

函数 ngramSearchCaseInsensitive, ngramSearchUTF8, ngramSearchCaseInsensitiveUTF8 提供此函数的不区分大小写以及/或 UTF-8 变体。

:::note UTF-8 变体使用了 3-gram 距离。这些并不是完全公平的 n-gram 距离。我们使用 2 字节的哈希函数来哈希 n-gram然后计算这些哈希表之间的(非)对称差异——可能会发生冲突。在使用 UTF-8 大小写不敏感格式时,我们并不使用公平的 tolower 函数——我们将每个码点字节的第 5 位(从零开始)和第零字节的第一个比特位位置为零(如果该串的大小超过一个字节)——这对拉丁字母和大部分西里尔字母都有效。 :::

语法

ngramSearch(haystack, needle)

countSubstrings

返回字符串 haystack 中子字符串 needle 出现的次数。

函数 countSubstringsCaseInsensitivecountSubstringsCaseInsensitiveUTF8 提供此函数的不区分大小写以及 UTF-8 变体。

语法

countSubstrings(haystack, needle[, start_pos])

参数

  • haystack — 被搜索的字符串,类型为String.
  • needle — 用于搜索的模式子字符串,类型为String.
  • start_pos 在字符串haystack 中开始检索的位置(从 1 开始),类型为UInt,可选。

返回值

  • 子字符串出现的次数。

数据类型: UInt64.

示例

SELECT countSubstrings('aaaa', 'aa');

结果:

┌─countSubstrings('aaaa', 'aa')─┐
│                             2 │
└───────────────────────────────┘

示例,使用参数 start_pos :

SELECT countSubstrings('abc___abc', 'abc', 4);

结果:

┌─countSubstrings('abc___abc', 'abc', 4)─┐
│                                      1 │
└────────────────────────────────────────┘

countMatches

返回正则表达式 patternhaystack 中成功匹配的次数。

语法

countMatches(haystack, pattern)

参数

返回值

  • 匹配次数。

数据类型: UInt64.

示例

SELECT countMatches('foobar.com', 'o+');

结果:

┌─countMatches('foobar.com', 'o+')─┐
│                                2 │
└──────────────────────────────────┘
SELECT countMatches('aaaa', 'aa');

结果:

┌─countMatches('aaaa', 'aa')────┐
│                             2 │
└───────────────────────────────┘

countMatchesCaseInsensitive

类似于 countMatches(haystack, pattern) 但是不区分大小写。

regexpExtract

提取匹配正则表达式模式的字符串haystack中的第一个字符串,并对应于正则表达式组索引。

语法

regexpExtract(haystack, pattern[, index])

别名: REGEXP_EXTRACT(haystack, pattern[, index]).

参数

  • haystack — 被匹配字符串,类型为String.
  • pattern — 正则表达式,必须是常量。类型为String.
  • index 一个大于等于 0 的整数,默认为 1 ,它代表要提取哪个正则表达式组。 UInt or Int 可选。

返回值

pattern可以包含多个正则组, index 代表要提取哪个正则表达式组。如果 index 为 0则返回整个匹配的字符串。

数据类型: String.

示例

SELECT
    regexpExtract('100-200', '(\\d+)-(\\d+)', 1),
    regexpExtract('100-200', '(\\d+)-(\\d+)', 2),
    regexpExtract('100-200', '(\\d+)-(\\d+)', 0),
    regexpExtract('100-200', '(\\d+)-(\\d+)');

结果:

┌─regexpExtract('100-200', '(\\d+)-(\\d+)', 1)─┬─regexpExtract('100-200', '(\\d+)-(\\d+)', 2)─┬─regexpExtract('100-200', '(\\d+)-(\\d+)', 0)─┬─regexpExtract('100-200', '(\\d+)-(\\d+)')─┐
│ 100                                          │ 200                                          │ 100-200                                      │ 100                                       │
└──────────────────────────────────────────────┴──────────────────────────────────────────────┴──────────────────────────────────────────────┴───────────────────────────────────────────┘

hasSubsequence

如果needlehaystack的子序列返回1否则返回0。 子序列是从给定字符串中删除零个或多个元素而不改变剩余元素的顺序得到的序列。

语法

hasSubsequence(haystack, needle)

参数

  • haystack — 被搜索的字符串,类型为String.
  • needle — 搜索子序列,类型为String.

返回值

  • 1, 如果needlehaystack的子序列
  • 0, 如果needle不是haystack的子序列

数据类型: UInt8.

示例

SELECT hasSubsequence('garbage', 'arg') ;

结果:

┌─hasSubsequence('garbage', 'arg')─┐
│                                1 │
└──────────────────────────────────┘

hasSubsequenceCaseInsensitive

类似于 hasSubsequence 但是不区分大小写。

hasSubsequenceUTF8

类似于 hasSubsequence 但是假定 haystackneedle 是 UTF-8 编码的字符串。

hasSubsequenceCaseInsensitiveUTF8

类似于 hasSubsequenceUTF8 但是不区分大小写。