跳到主要内容

模式匹配

Goose 提供四种独立的模式匹配方式: 传统 SQL 的 LIKE 运算符, 较新的 SIMILAR TO 运算符(在 SQL:1999 中加入), GLOB 运算符, 以及 POSIX 风格的正则表达式

LIKE

如果字符串匹配给定模式,LIKE 表达式返回 true。(同理,若 LIKE 返回 trueNOT LIKE 就返回 false,反之亦然。等价表达式为 NOT (string LIKE pattern)。)

如果模式中不包含百分号或下划线,则该模式只表示字符串本身;此时 LIKE 的行为等同于等号运算符。模式中的下划线(_)表示(匹配)任意单个字符;百分号(%)匹配长度为零或更多字符的任意序列。

LIKE 模式匹配始终覆盖整个字符串。因此,如果希望匹配字符串中任意位置的子串,模式必须以百分号开头并以百分号结尾。

示例:

SELECT 'abc' LIKE 'abc';    -- true
SELECT 'abc' LIKE 'a%' ; -- true
SELECT 'abc' LIKE '_b_'; -- true
SELECT 'abc' LIKE 'c'; -- false
SELECT 'abc' LIKE 'c%' ; -- false
SELECT 'abc' LIKE '%c'; -- true
SELECT 'abc' NOT LIKE '%c'; -- false

关键字 ILIKE 可以替代 LIKE,并根据当前区域设置执行不区分大小写匹配:

SELECT 'abc' ILIKE '%C'; -- true
SELECT 'abc' NOT ILIKE '%C'; -- false

若要在字符串中搜索通配符字符(%_)本身,模式必须使用 ESCAPE 子句和转义字符,以指示该通配符应按字面字符处理,而不是通配符。见下方示例。

此外,函数 like_escape 与带 ESCAPE 子句的 LIKE 表达式功能相同,但采用函数语法。详情请参阅文本函数文档

搜索包含 'a'、接着是字面百分号、再接着 'c' 的字符串:

SELECT 'a%c' LIKE 'a$%c' ESCAPE '$'; -- true
SELECT 'azc' LIKE 'a$%c' ESCAPE '$'; -- false

结合 ESCAPE 的不区分大小写 ILIKE

SELECT 'A%c' ILIKE 'a$%c' ESCAPE '$'; -- true

还可以使用以下替代符号来表示 LIKE 相关表达式,以增强 PostgreSQL 兼容性。

PostgreSQL 风格LIKE 风格
~~LIKE
!~~NOT LIKE
~~*ILIKE
!~~*NOT ILIKE

SIMILAR TO

SIMILAR TO 运算符根据其模式是否匹配给定字符串返回 true 或 false。它与 LIKE 类似,但会使用正则表达式来解释模式。与 LIKE 一样,SIMILAR TO 仅在模式匹配整个字符串时才算匹配成功;这不同于常见正则表达式可匹配字符串任意部分的行为。

正则表达式是一个字符序列,用于以简写形式定义一组字符串(正则集合)。当某个字符串属于该正则表达式描述的集合时,称其匹配该正则表达式。与 LIKE 类似,模式字符默认按字面精确匹配字符串字符,除非它们在正则表达式语言中是特殊字符——但正则表达式使用的特殊字符与 LIKE 不同。

示例:

SELECT 'abc' SIMILAR TO 'abc';       -- true
SELECT 'abc' SIMILAR TO 'a'; -- false
SELECT 'abc' SIMILAR TO '.*(b|d).*'; -- true
SELECT 'abc' SIMILAR TO '(b|c).*'; -- false
SELECT 'abc' NOT SIMILAR TO 'abc'; -- false

In PostgreSQL, ~ is equivalent to SIMILAR TO and !~ is equivalent to NOT SIMILAR TO. In Goose, these equivalences do not hold currently, see the PostgreSQL compatibility page.

在 PostgreSQL 中,~ 等价于 SIMILAR TO!~ 等价于 NOT SIMILAR TO。 但在 Goose 中目前并非如此, 详见 PostgreSQL 兼容性页面

Globbing

Goose 支持文件名展开(也称 globbing)用于发现文件。 Goose 的 glob 语法中,问号(?)通配任意单个字符,星号(*)通配零个或多个字符。 此外,你还可以使用方括号语法([...])匹配方括号内任意单个字符,或方括号指定范围内的任意单个字符。可在首个方括号内使用感叹号(!)来匹配不在该集合中的字符。 更多信息可参阅 “glob (programming)” 维基百科页面

GLOB

当字符串匹配 GLOB 模式时,GLOB 运算符返回 true,否则返回 falseGLOB 最常用于按特定模式(例如某个文件扩展名)搜索文件名。

示例:

SELECT 'best.txt' GLOB '*.txt';            -- true
SELECT 'best.txt' GLOB '????.txt'; -- true
SELECT 'best.txt' GLOB '?.txt'; -- false
SELECT 'best.txt' GLOB '[abc]est.txt'; -- true
SELECT 'best.txt' GLOB '[a-z]est.txt'; -- true

方括号语法区分大小写:

SELECT 'Best.txt' GLOB '[a-z]est.txt';     -- false
SELECT 'Best.txt' GLOB '[a-zA-Z]est.txt'; -- true

! 作用于方括号内定义的整个字符集合:

SELECT 'Best.txt' GLOB '[!a-zA-Z]est.txt'; -- false

如需对 GLOB 运算符取反,应对整个表达式取反:

SELECT NOT 'best.txt' GLOB '*.txt';        -- false

也可以使用三个波浪号(~~~)替代 GLOB 关键字。

GLOB 风格符号风格
GLOB~~~

使用 Glob 函数查找文件名

glob 模式匹配语法也可通过 glob 表函数用于搜索文件名。 它接收一个参数:要搜索的路径(可包含 glob 模式)。

搜索当前目录下的所有文件:

SELECT * FROM glob('*');
file
goose.exe
test.csv
test.json
test.parquet
test2.csv
test2.parquet
todos.json

Globbing 语义

Goose 的 globbing 实现遵循 Python glob 的语义,而不是 shell 中 glob 的语义。 一个显著差异是 **/ 结构的行为:**/⟨filename⟩ 不会返回位于顶层目录中的 ⟨filename⟩ 文件。 例如,目录中存在 README.mdx 文件时,以下查询可以找到它:

SELECT * FROM glob('README.mdx');
file
README.mdx

但下面的查询会返回空结果:

SELECT * FROM glob('**/README.mdx');

而 Bash、Zsh 等 shell 的 globbing 在相同语法下可以找到该文件:

ls **/README.mdx
README.mdx

Regular Expressions

Goose 对正则表达式的支持记录在正则表达式页面。 Goose 支持一些 PostgreSQL 风格的正则匹配运算符:

PostgreSQL 风格等价表达式
~regexp_full_match
!~NOT regexp_full_match
~*(not supported)
!~*(not supported)