> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/man/regex/regex.3.md).

# regex.3

`regcomp` — 正则表达式库

## 名称

`regcomp`, `regexec`, `regerror`, `regfree`

## 库

Lb libc

## 概要

`#include <regex.h>`

```c
int
regcomp(regex_t *restrict preg, const char *restrict pattern,
    int cflags);

int
regexec(const regex_t *restrict preg, const char *restrict string,
    size_t nmatch, regmatch_t pmatch[restrict], int eflags);

size_t
regerror(int errcode, const regex_t *restrict preg,
    char *restrict errbuf, size_t errbuf_size);

void
regfree(regex_t *preg);
```

## 描述

这些例程实现了 IEEE Std 1003.2 ("POSIX.2") 正则表达式（"RE"）；参见 re\_format(7)。`regcomp` 函数将以字符串形式编写的 RE 编译为内部形式，`regexec` 将该内部形式与字符串进行匹配并报告结果，`regerror` 将两者的错误代码转换为人类可读的消息，`regfree` 释放 RE 内部形式所使用的任何动态分配的存储空间。

头文件

```c
#include <regex.h>
```

声明了两个结构类型，`regex_t` 和 `regmatch_t`，前者用于编译后的内部形式，后者用于匹配报告。它还声明了这四个函数、一个 `regoff_t` 类型，以及许多名称以 "`REG_`" 开头的常量。

`regcomp` 函数编译包含在 `pattern` 字符串中的正则表达式，受 `cflags` 中的标志约束，并将结果放入 `preg` 所指向的 `regex_t` 结构中。`cflags` 参数是以下零个或多个标志的按位或：

**`REG_EXTENDED`** 编译现代（"扩展"）RE，而不是默认的过时（"基本"）RE。

**`REG_BASIC`** 这是 0 的同义词，作为 `REG_EXTENDED` 的对应项提供，以提高可读性。

**`REG_NOSPEC`** 编译时关闭所有特殊字符的识别。因此所有字符都被视为普通字符，"RE" 即为字面字符串。这是一个扩展，与 IEEE Std 1003.2 ("POSIX.2") 兼容但未被其规定，在意图移植到其他系统的软件中应谨慎使用。`REG_EXTENDED` 和 `REG_NOSPEC` 不能在同一次 `regcomp` 调用中同时使用。

**`REG_ICASE`** 编译用于忽略大小写区分的匹配。参见 re\_format(7)。

**`REG_NOSUB`** 编译用于只需报告成功或失败而无需报告匹配内容的匹配。

**`REG_NEWLINE`** 编译用于换行符敏感的匹配。默认情况下，换行符是一个完全普通的字符，在 RE 或字符串中没有任何特殊含义。使用此标志时，`[^` 括号表达式和 `.` 永不匹配换行符，`^` 锚点除了其正常功能外，还匹配字符串中任何换行符之后的空字符串，`$` 锚点除了其正常功能外，还匹配字符串中任何换行符之前的空字符串。

**`REG_PEND`** 正则表达式不在第一个 NUL 处结束，而是在 `preg` 所指向结构的 `re_endp` 成员所指向的字符之前结束。`re_endp` 成员的类型为 `const char *`。此标志允许在 RE 中包含 NUL；它们被视为普通字符。这是一个扩展，与 IEEE Std 1003.2 ("POSIX.2") 兼容但未被其规定，在意图移植到其他系统的软件中应谨慎使用。

**`REG_POSIX`** 仅编译符合 IEEE Std 1003.2 ("POSIX.2") 的表达式。除非链接 `libregex`，否则此标志无效。这是一个扩展，与 IEEE Std 1003.2 ("POSIX.2") 兼容但未被其规定，在意图移植到其他系统的软件中应谨慎使用。

成功时，`regcomp` 返回 0 并填充 `preg` 所指向的结构。该结构的一个成员（`re_endp` 除外）是公开的：`re_nsub`，类型为 `size_t`，包含 RE 中括号括起的子表达式数量（但如果使用了 `REG_NOSUB` 标志，该成员的值未定义）。如果 `regcomp` 失败，返回非零错误代码；参见诊断一节。

`regexec` 函数将 `preg` 所指向的已编译 RE 与 `string` 进行匹配，受 `eflags` 中的标志约束，并使用 `nmatch`、`pmatch` 和返回值报告结果。该 RE 必须由之前调用 `regcomp` 编译。编译形式在 `regexec` 执行期间不会被修改，因此单个编译的 RE 可同时被多个线程使用。

默认情况下，`string` 所指向的以 NUL 结尾的字符串被视为整行文本，不包括任何终止换行符。`eflags` 参数是以下零个或多个标志的按位或：

**`REG_NOTBOL`** 字符串的第一个字符被视为某一行的延续。这意味着锚点 `^`、`[[:<:]]` 和 `\<` 在其之前不匹配；但参见下文的 `REG_STARTEND`。这不影响 `REG_NEWLINE` 下换行符的行为。

**`REG_NOTEOL`** 终止字符串的 NUL 不结束一行，因此 `$` 锚点在其之前不匹配。这不影响 `REG_NEWLINE` 下换行符的行为。

**`REG_STARTEND`** 字符串被视为从 `string` + `pmatch`\[0].`rm_so` 开始，在 `string` + `pmatch`\[0].`rm_eo` 所指向的字节之前结束，无论 `nmatch` 的值如何。`pmatch` 和 `nmatch` 的定义见下文。这是一个扩展，与 IEEE Std 1003.2 ("POSIX.2") 兼容但未被其规定，在意图移植到其他系统的软件中应谨慎使用。未指定 `REG_NOTBOL` 时，位置 `rm_so` 被视为行的开头，`^` 在其之前匹配；如果该位置是单词字符，则视为单词开头，`[[:<:]]` 和 `\<` 在其之前匹配。指定 `REG_NOTBOL` 时，位置 `rm_so` 处的字符被视为行的延续，如果 `rm_so` 大于 0，则考虑前一个字符。如果前一个字符是换行符且正则表达式使用 `REG_NEWLINE` 编译，`^` 在字符串之前匹配；如果前一个字符不是单词字符但字符串以单词字符开头，`[[:<:]]` 和 `\<` 在字符串之前匹配。

关于在 RE 或其一部分可以匹配 `string` 的多个子字符串中的任何一个时实际匹配什么，参见 re\_format(7) 的讨论。

通常，`regexec` 成功时返回 0，失败时返回非零代码 `REG_NOMATCH`。在异常情况下可能返回其他非零错误代码；参见诊断一节。

如果在 RE 的编译中指定了 `REG_NOSUB`，或者 `nmatch` 为 0，`regexec` 忽略 `pmatch` 参数（但指定 `REG_STARTEND` 的情况见下文）。否则，`pmatch` 指向一个包含 `nmatch` 个 `regmatch_t` 类型结构的数组。这样的结构至少有 `rm_so` 和 `rm_eo` 两个成员，均为 `regoff_t` 类型（一种至少与 `off_t` 和 `ssize_t` 一样大的有符号算术类型），分别包含子字符串首字符的偏移量和子字符串结束后第一个字符的偏移量。偏移量从传递给 `regexec` 的 `string` 参数的开头计算。空子字符串由相等的偏移量表示，两者都指向空子字符串之后的字符。

`pmatch` 数组的第 0 个成员被填充以指示 `string` 的哪个子字符串被整个 RE 匹配。其余成员报告 RE 中括号括起的子表达式匹配了哪个子字符串；成员 `i` 报告子表达式 `i`，子表达式按其左括号在 RE 中的顺序从左到右编号（从 1 开始）。数组中未使用的条目（对应于完全未参与匹配的子表达式，或 RE 中不存在的子表达式，即 `i` > `preg`->`re_nsub`）的 `rm_so` 和 `rm_eo` 均设置为 -1。如果某个子表达式参与了多次匹配，报告的子字符串是它最后一次匹配的子字符串。（特别注意，当 RE `(b*)+` 匹配 `bbb` 时，括号括起的子表达式匹配三个 'b' 中的每一个，然后匹配最后一个 `b` 之后的无限个空字符串，因此报告的子字符串是其中一个空字符串。）

如果指定了 `REG_STARTEND`，`pmatch` 必须指向至少一个 `regmatch_t`（即使 `nmatch` 为 0 或指定了 `REG_NOSUB`），以保存 `REG_STARTEND` 的输入偏移量。用于输出仍完全由 `nmatch` 控制；如果 `nmatch` 为 0 或指定了 `REG_NOSUB`，`pmatch`\[0] 的值不会被成功的 `regexec` 改变。

`regerror` 函数将来自 `regcomp` 或 `regexec` 的非零 `errcode` 映射为人类可读的可打印消息。如果 `preg` 非 `NULL`，错误代码应来自使用 `preg` 所指向的 `regex_t`，且如果错误代码来自 `regcomp`，它应是使用该 `regex_t` 的最近一次 `regcomp` 的结果。（`regerror` 可能能够使用 `regex_t` 中的信息提供更详细的消息。）`regerror` 函数将以 NUL 结尾的消息放入 `errbuf` 所指向的缓冲区，将长度（包括 NUL）限制为最多 `errbuf_size` 字节。如果整个消息无法容纳，则提供终止 NUL 之前能容纳的部分。无论哪种情况，返回值都是保存整个消息（包括终止 NUL）所需的缓冲区大小。如果 `errbuf_size` 为 0，忽略 `errbuf`，但返回值仍然正确。

如果传递给 `regerror` 的 `errcode` 先与 `REG_ITOA` 进行或运算，则得到的"消息"是错误代码的可打印名称，例如 "`REG_NOMATCH`"，而不是其解释。如果 `errcode` 为 `REG_ATOI`，则 `preg` 应非 `NULL`，且其指向结构的 `re_endp` 成员必须指向某个错误代码的可打印名称；在这种情况下，`errbuf` 中的结果是错误代码数值的十进制数字（如果名称未被识别则为 0）。`REG_ITOA` 和 `REG_ATOI` 主要用作调试工具；它们是扩展，与 IEEE Std 1003.2 ("POSIX.2") 兼容但未被其规定，在意图移植到其他系统的软件中应谨慎使用。还要注意，它们被视为实验性的，可能会发生变化。

`regfree` 函数释放与 `preg` 所指向的已编译 RE 关联的任何动态分配的存储空间。剩余的 `regex_t` 不再是有效的已编译 RE，将其提供给 `regexec` 或 `regerror` 的效果未定义。

这些函数都不引用全局变量（常量表除外）；如果参数是安全的，所有函数都可以安全地从多个线程使用。

## 实现选择

有许多决策由 IEEE Std 1003.2 ("POSIX.2") 留给实现者，要么明确说"未定义"，要么由于 RE 语法禁止它们。本实现如下处理。

关于大小写无关匹配定义的讨论，参见 re\_format(7)。

RE 的长度没有特定限制，除了内存有限。内存使用量与 RE 大致成线性关系，且在很大程度上对 RE 复杂度不敏感，但有界重复除外。参见缺陷一节中一个使用有界重复的短 RE，它将使几乎所有系统耗尽内存。

除 IEEE Std 1003.2 ("POSIX.2") 特别赋予魔法含义的反斜杠字符外（此类魔法含义仅出现在过时的 \["基本"] RE 中），其他反斜杠字符被视为普通字符。

任何未匹配的 `[` 都是 `REG_EBRACK` 错误。

等价类不能开始或结束括号表达式范围。一个范围的端点不能开始另一个范围。

`RE_DUP_MAX`，即有界重复中重复计数的限制，为 255。

重复运算符（`?`、`*`、`+` 或界限）不能跟在另一个重复运算符之后。重复运算符不能开始一个表达式或子表达式，也不能跟在 `^` 或 `|` 之后。

`|` 不能出现在（子）表达式的开头或结尾，也不能跟在另一个 `|` 之后，即 `|` 的操作数不能是空子表达式。空的括号括起子表达式 `()` 是合法的，匹配空（子）字符串。空字符串不是合法的 RE。

后跟数字的 `{` 被视为有界重复界限的开始，随后必须遵循界限语法。不跟数字的 `{` 被视为普通字符。

在过时（"基本"）RE 中，开始和结束子表达式的 `^` 和 `$` 是锚点，而非普通字符。

## 诊断

来自 `regcomp` 和 `regexec` 的非零错误代码包括：

**`REG_NOMATCH`** `regexec` 函数匹配失败

**`REG_BADPAT`** 无效的正则表达式

**`REG_ECOLLATE`** 无效的整理元素

**`REG_ECTYPE`** 无效的字符类

**`REG_EESCAPE`** `\` 应用于不可转义的字符

**`REG_ESUBREG`** 无效的反向引用编号

**`REG_EBRACK`** 方括号 `[ ]` 不平衡

**`REG_EPAREN`** 圆括号 `( )` 不平衡

**`REG_EBRACE`** 花括号 `{ }` 不平衡

**`REG_BADBR`** `{ }` 中的重复计数无效

**`REG_ERANGE`** `[ ]` 中的字符范围无效

**`REG_ESPACE`** 内存耗尽

**`REG_BADRPT`** `?`、`*` 或 `+` 的操作数无效

**`REG_EMPTY`** 空（子）表达式

**`REG_ASSERT`** 不可能发生——你发现了一个 bug

**`REG_INVARG`** 无效参数，例如负长度字符串

**`REG_ILLSEQ`** 非法字节序列（错误的多字节字符）

## 参见

[grep(1)](/man/man1/grep.1.md), re\_format(7)

IEEE Std 1003.2 ("POSIX.2") 第 2.8 节（正则表达式表示法）和 B.5 节（正则表达式匹配的 C 绑定）。

## 历史

最初由 Henry Spencer 编写。经修改后纳入 4.4BSD 发行版。

## 缺陷

这是一个 alpha 版本，存在已知缺陷。请报告问题。

反向引用代码较为微妙，在复杂情况下其正确性仍有疑虑。

`regexec` 函数性能较差。这将在后续版本中改进。`nmatch` 参数超过 0 开销较大；`nmatch` 超过 1 更糟。`regexec` 函数在很大程度上对 RE 复杂度不敏感，*但*反向引用的开销极大。RE 长度确实有影响；特别是，将 RE 长度保持在约 30 个字符以下有显著的速度优势，大多数特殊字符大致按双倍计算。

`regcomp` 函数通过宏展开实现有界重复，如果计数很大或有界重复嵌套，在时间和空间上开销都很大。例如 `((((a{1,100}){1,100}){1,100}){1,100}){1,100}` 这样的 RE 将（最终）使几乎所有现有机器耗尽交换空间。

对罕见错误条件的响应存在疑似问题。特别是，某些类型的内部溢出（仅由真正巨大的 RE 或多层嵌套的有界重复产生）可能处理不当。

由于 IEEE Std 1003.2 ("POSIX.2") 中的一个错误，像 `a)b` 这样的表达式是合法的 RE，因为 `)` 只有在存在先前未匹配的 `(` 时才是特殊字符。在规范修复之前无法修复此问题。

标准对反向引用的定义模糊。例如，`a\(\(b\)*\2\)*d` 是否匹配 `abbbd`？在标准澄清之前，不应依赖此类情况下的行为。

词边界匹配的实现有些取巧，词边界匹配与锚定的组合中可能隐藏 bug。

词边界匹配在多字节 locale 中无法正常工作。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://book.bsdcn.org/man/regex/regex.3.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
