字符串搜索函数
本节中的所有函数默认情况下都区分大小写进行搜索。不区分大小写的搜索通常由单独的函数变体提供。
请注意,不区分大小写的搜索,遵循英语的小写-大写规则。
例如。英语中大写的i是I,而在土耳其语中则是İ, 对于英语以外 的语言,结果可能会不符合预期。
本节中的函数还假设搜索字符串和被搜索字符串是单字节编码文本(例如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 >= 1且start_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 但交换了 haystack 和 locate 参数。
此函数的行为取决于 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 但是假定 haystack 和 needle 是 UTF-8 编码的字符串。
示例
函数 positionUTF8 可以正确的将字符 ö 计为单个 Unicode 代码点(ö由两个点表示):
SELECT positionUTF8('Motörhead', 'r');
结果:
┌─position('Motörhead', 'r')─┐
│ 5 │
└────────────────────────────┘
positionCaseInsensitiveUTF8
类似于 positionUTF8 但是不区分大小写。
multiSearchAllPositions
类似于 position 但是返回多个在字符串 haystack 中 needle 子字符串的位置的数组(以字节为单位,从 1 开始)。
所有以 multiSearch*() 开头的函数仅支持最多 28 个needle.
语法
multiSearchAllPositions(haystack, [needle1, needle2, ..., needleN])
参数
返回值
- 位置数组,数组中的每个元素对应于
needle数组中的一个元素。如果在haystack中找到子字符串,则返回的数组中的元素为子字符串的位置(以字节为单位,从 1 开始);如果未找到子字符串,则返回的数组中的元素为 0。
示例
SELECT multiSearchAllPositions('Hello, World!', ['hello', '!', 'world']);
结果:
┌─multiSearchAllPositions('Hello, World!', ['hello', '!', 'world'])─┐
│ [0,13,0] │
└───────────────────────────────────────────────────────────────────┘
multiSearchAllPositionsUTF8
类似于 multiSearchAllPositions ,但假定 haystack 和 needle-s 是 UTF-8 编码的字符串。
multiSearchFirstPosition
类似于 position , 在字符串haystack中匹配多个needle子字符串,从左开始任一匹配的子串,返回其位置。
函数 multiSearchFirstPositionCaseInsensitive, multiSearchFirstPositionUTF8 和 multiSearchFirstPositionCaseInsensitiveUTF8 提供此函数的不区分大小写 以及/或 UTF-8 变体。
语法
multiSearchFirstPosition(haystack, [needle1, needle2, ..., needleN])
multiSearchFirstIndex
在字符串haystack中匹配最左侧的 needlei 子字符串,返回其索引 i (从1开始),如无法匹配则返回0。
函数 multiSearchFirstIndexCaseInsensitive, multiSearchFirstIndexUTF8 和 multiSearchFirstIndexCaseInsensitiveUTF8 提供此函数的不区分大小写以及/或 UTF-8 变体。
语法
multiSearchFirstIndex(haystack, \[needle<sub>1</sub>, needle<sub>2</sub>, ..., needle<sub>n</sub>\])
multiSearchAny
至少已有一个子字符串needle匹配 haystack 时返回1,否则返回 0 。
函数 multiSearchAnyCaseInsensitive, multiSearchAnyUTF8 和 multiSearchAnyCaseInsensitiveUTF8 提供此函数的不区分大小写以及/或 UTF-8 变体。
语法
multiSearchAny(haystack, [needle1, needle2, ..., needleN])
match
返回字符串 haystack 是否匹配正则表达式 pattern (re2正则语法参考
匹配基于 UTF-8,例如. 匹配 Unicode 代码点 ¥,它使用两个字节以 UTF-8 表示。T正则表达式不得包含空字节。如果 haystack 或pattern不是有效的 UTF-8,则此行为为undefined。
与 re2 的默认行为不同,. 会匹配换行符。要禁用此功能,请在模式前面添加(?-s)。
如果仅希望搜索子字符串,可以使用函数 like或 position 来替代,这些函数的性能比此函数更高。
语法
match(haystack, pattern)
别名: haystack REGEXP pattern operator
multiMatchAny
类似于 match,如果至少有一个表达式 pattern<sub>i</sub> 匹配字符串 haystack,则返回1,否则返回0。
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,但与非模糊搜索相比,它的开销总是更高的。
由于 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.
返回值
- 数据类型: Array.
如果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.
返回值
- 数据类型: Array.
如果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 表示。
如果 haystack 或 LIKE 表达式不是有效的 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,则抛出异常。如果参数 haystack 或 needle 是非常数且大小超过 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 变体。
UTF-8 变体使用了 3-gram 距离。这些并不是完全公平的 n-gram 距离。我们使用 2 字节的哈希函数来哈希 n-gram,然后计算这些哈希表之间的(非)对称差异——可能会发生冲突。在使用 UTF-8 大小写不敏感格式时,我们并不使用公平的 tolower 函数——我们将每个码点字节的第 5 位(从零开始)和第零字节的第一个比特位位置为零(如果该串的大小超过一个字节)——这对拉丁字母和大部分西里尔字母都有效。
语法
ngramSearch(haystack, needle)
countSubstrings
返回字符串 haystack 中子字符串 needle 出现的次数。
函数 countSubstringsCaseInsensitive 和 countSubstringsCaseInsensitiveUTF8 提供此函数的不区分大小写以及 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
返回正则表达式 pattern 在 haystack 中成功匹配的次数。
语法
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
如果needle是haystack的子序列,返回1,否则返回0。
子序列是从给定字符串中删除零个或多个元素而不改变剩余元素的顺序得到的序列。
语法
hasSubsequence(haystack, needle)
参数
返回值
- 1, 如果
needle是haystack的子序列 - 0, 如果
needle不是haystack的子序列
数据类型: UInt8.
示例
SELECT hasSubsequence('garbage', 'arg') ;
结果:
┌─hasSubsequence('garbage', 'arg')─┐
│ 1 │
└──────────────────────────────────┘
hasSubsequenceCaseInsensitive
类似于 hasSubsequence 但是不区分大小写。
hasSubsequenceUTF8
类似于 hasSubsequence 但是假定 haystack 和 needle 是 UTF-8 编码的字符串。
hasSubsequenceCaseInsensitiveUTF8
类似于 hasSubsequenceUTF8 但是不区分大小写。