Java 正则表达式语法规则、字典、索引

本文深入解析正则表达式的各个元素及其用法,包括特殊字符、元字符、断言、字符集、范围、引用等,并通过实例展示其在实际场景中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

字符

说明

\

将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如,"n"匹配字符"n"。"\n"匹配换行符。序列"\\"匹配"\","\("匹配"("。

^

匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与"\n"或"\r"之后的位置匹配。

$

匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与"\n"或"\r"之前的位置匹配。

*

零次或多次匹配前面的字符或子表达式。例如,zo* 匹配"z"和"zoo"。* 等效于 {0,}。

+

一次或多次匹配前面的字符或子表达式。例如,"zo+"与"zo"和"zoo"匹配,但与"z"不匹配。+ 等效于 {1,}。

?

零次或一次匹配前面的字符或子表达式。例如,"do(es)?"匹配"do"或"does"中的"do"。? 等效于 {0,1}。

{n}

是非负整数。正好匹配 n 次。例如,"o{2}"与"Bob"中的"o"不匹配,但与"food"中的两个"o"匹配。

{n,}

是非负整数。至少匹配 次。例如,"o{2,}"不匹配"Bob"中的"o",而匹配"foooood"中的所有 o。"o{1,}"等效于"o+"。"o{0,}"等效于"o*"。

{n,m}

M 和 n 是非负整数,其中 n <= m。匹配至少 n 次,至多 m 次。例如,"o{1,3}"匹配"fooooood"中的头三个 o。'o{0,1}' 等效于 'o?'。注意:您不能将空格插入逗号和数字之间。

?

当此字符紧随任何其他限定符(*、+、?、{n}、{n,}、{n,m})之后时,匹配模式是"非贪心的"。"非贪心的"模式匹配搜索到的、尽可能短的字符串,而默认的"贪心的"模式匹配搜索到的、尽可能长的字符串。例如,在字符串"oooo"中,"o+?"只匹配单个"o",而"o+"匹配所有"o"。

.

匹配除"\r\n"之外的任何单个字符。若要匹配包括"\r\n"在内的任意字符,请使用诸如"[\s\S]"之类的模式。

(pattern)

匹配 pattern 并捕获该匹配的子表达式。可以使用 $0…$9 属性从结果"匹配"集合中检索捕获的匹配。若要匹配括号字符 ( ),请使用"\("或者"\)"。

(?:pattern)

匹配 pattern 但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用"or"字符 (|) 组合模式部件的情况很有用。例如,'industr(?:y|ies) 是比 'industry|industries' 更经济的表达式。

(?=pattern)

执行正向预测先行搜索的子表达式,该表达式匹配处于匹配 pattern 的字符串的起始点的字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,'Windows (?=95|98|NT|2000)' 匹配"Windows 2000"中的"Windows",但不匹配"Windows 3.1"中的"Windows"。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。

(?!pattern)

执行反向预测先行搜索的子表达式,该表达式匹配不处于匹配 pattern 的字符串的起始点的搜索字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,'Windows (?!95|98|NT|2000)' 匹配"Windows 3.1"中的 "Windows",但不匹配"Windows 2000"中的"Windows"。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。

x|y

匹配 x 或 y。例如,'z|food' 匹配"z"或"food"。'(z|f)ood' 匹配"zood"或"food"。

[xyz]

字符集。匹配包含的任一字符。例如,"[abc]"匹配"plain"中的"a"。

[^xyz]

反向字符集。匹配未包含的任何字符。例如,"[^abc]"匹配"plain"中"p","l","i","n"。

[a-z]

字符范围。匹配指定范围内的任何字符。例如,"[a-z]"匹配"a"到"z"范围内的任何小写字母。

[^a-z]

反向范围字符。匹配不在指定的范围内的任何字符。例如,"[^a-z]"匹配任何不在"a"到"z"范围内的任何字符。

\b

匹配一个字边界,即字与空格间的位置。例如,"er\b"匹配"never"中的"er",但不匹配"verb"中的"er"。

\B

非字边界匹配。"er\B"匹配"verb"中的"er",但不匹配"never"中的"er"。

\cx

匹配 x 指示的控制字符。例如,\cM 匹配 Control-M 或回车符。x 的值必须在 A-Z 或 a-z 之间。如果不是这样,则假定 c 就是"c"字符本身。

\d

数字字符匹配。等效于 [0-9]。

\D

非数字字符匹配。等效于 [^0-9]。

\f

换页符匹配。等效于 \x0c 和 \cL。

\n

换行符匹配。等效于 \x0a 和 \cJ。

\r

匹配一个回车符。等效于 \x0d 和 \cM。

\s

匹配任何空白字符,包括空格、制表符、换页符等。与 [ \f\n\r\t\v] 等效。

\S

匹配任何非空白字符。与 [^ \f\n\r\t\v] 等效。

\t

制表符匹配。与 \x09 和 \cI 等效。

\v

垂直制表符匹配。与 \x0b 和 \cK 等效。

\w

匹配任何字类字符,包括下划线。与"[A-Za-z0-9_]"等效。

\W

与任何非单词字符匹配。与"[^A-Za-z0-9_]"等效。

\xn

匹配 n,此处的 n 是一个十六进制转义码。十六进制转义码必须正好是两位数长。例如,"\x41"匹配"A"。"\x041"与"\x04"&"1"等效。允许在正则表达式中使用 ASCII 代码。

\num

匹配 num,此处的 num 是一个正整数。到捕获匹配的反向引用。例如,"(.)\1"匹配两个连续的相同字符。

\n

标识一个八进制转义码或反向引用。如果 \n 前面至少有 n 个捕获子表达式,那么 n 是反向引用。否则,如果 n 是八进制数 (0-7),那么 n 是八进制转义码。

\nm

标识一个八进制转义码或反向引用。如果 \nm 前面至少有 nm 个捕获子表达式,那么 nm 是反向引用。如果 \nm 前面至少有 n 个捕获,则 n 是反向引用,后面跟有字符 m。如果两种前面的情况都不存在,则 \nm 匹配八进制值 nm,其中和 m 是八进制数字 (0-7)。

\nml

当 n 是八进制数 (0-3),m 和 l 是八进制数 (0-7) 时,匹配八进制转义码 nml

\un

匹配 n,其中 n 是以四位十六进制数表示的 Unicode 字符。例如,\u00A9 匹配版权符号 (©)。


注:Java中,使用关键字需要加两个\,比如:“\\w”“\\(”

附:

前置断言和后置断言:比如:"(?<=\\.)[A-Z]\\w*?xception(?=: )"可以匹配并获取“### Error querying database.  Cause: java.lang.ArithmeticException: / by zero Exception”中的“ArithmeticException

  • (?<=xxx):前置断言,表示匹配xxx并去除
  • (?=yyy):后置断言,表示匹配yyy并去除



<think>我们正在讨论Python正则表达式中的命名捕获组。根据引用[1][2][3],命名捕获组使用语法`(?P<name>pattern)`,其中`name`是捕获组的名称,`pattern`是要匹配正则表达式。命名捕获组允许我们通过名称(而不仅仅是数字索引)来引用匹配的文本,这可以使正则表达式更易读和维护。 在Python中,我们可以使用`re`模块来使用命名捕获组。当匹配成功后,我们可以通过`match.group('name')`或`match.group(1)`(使用组号)来访问捕获的文本。注意,非捕获组(引用[4])使用`(?:pattern)`语法,它们不会保存匹配内容,因此无法通过`group`方法获取,但可以提高性能。 下面我将通过一个示例详细说明命名捕获组的使用方法,并解释相关概念。 ### 命名捕获组的基本使用 假设我们要从日期字符串"26-08-2024"中提取日、月、年。我们可以使用命名捕获组为每个部分命名。 ```python import re # 定义正则表达式,使用命名捕获组 pattern = r'(?P<dd>\d{2})-(?P<mm>\d{2})-(?P<yyyy>\d{4})' date_string = "26-08-2024" # 使用re.search进行匹配 match = re.search(pattern, date_string) if match: # 通过组名获取匹配内容 day = match.group('dd') month = match.group('mm') year = match.group('yyyy') print(f"日: {day}, 月: {month}, 年: {year}") # 也可以通过组号获取(按照出现的顺序,从1开始) print(f"使用组号1(dd): {match.group(1)}") print(f"使用组号2(mm): {match.group(2)}") print(f"使用组号3(yyyy): {match.group(3)}") # groups()返回所有捕获组(不包括非捕获组)的元组,按组号顺序 print(f"所有捕获组: {match.groups()}") # groupdict()返回一个字典,包含所有命名捕获组 print(f"命名捕获组字典: {match.groupdict()}") ``` 输出: ``` 日: 26, 月: 08, 年: 2024 使用组号1(dd): 26 使用组号2(mm): 08 使用组号3(yyyy): 2024 所有捕获组: ('26', '08', '2024') 命名捕获组字典: {'dd': '26', 'mm': '08', 'yyyy': '2024'} ``` ### 说明 1. **命名捕获组语法**:`(?P<name>pattern)` - 例如,`(?P<dd>\d{2})`定义了一个名为`dd`的捕获组,匹配两个数字。 2. **访问匹配内容**: - 使用`match.group('name')`通过组名访问。 - 使用`match.group(n)`通过组号访问(组号从1开始,按照左括号出现的顺序)。 - `match.groups()`返回所有捕获组(按组号顺序)组成的元组。 - `match.groupdict()`返回一个字典,其中键为组名,值为匹配的字符串。 3. **非捕获组**:如果不需要捕获某个分组,可以使用`(?:pattern)`。例如,如果我们不关心分隔符,可以写成: ```python pattern = r'(?P<dd>\d{2})-(?P<mm>\d{2})-(?P<yyyy>\d{4})' # 或者如果连字符不需要捕获,其实我们这里的分隔符并没有用分组,所以不需要改变。但如果中间有分组而我们不需要捕获,就可以用非捕获组。 # 例如:匹配日期,但中间的分隔符可能是空格或连字符,且我们不关心分隔符 pattern = r'(?P<dd>\d{2})(?:-|\s)(?P<mm>\d{2})(?:-|\s)(?P<yyyy>\d{4})' ``` 这样,中间的分隔符分组不会被保存,也不会出现在`groups()`或`groupdict()`中。 ### 注意事项 - 命名捕获组的名称必须唯一,否则会报错。 - 命名捕获组和普通捕获组(未命名的)可以混合使用,但普通捕获组仍然按顺序编号,命名捕获组不会影响普通捕获组的编号(它们一起按顺序编号)。 例如:`(a)(?P<name>b)(c)`,其中: - 组1:`a`(普通捕获组) - 组2:`b`(命名捕获组,名为`name`) - 组3:`c`(普通捕获组) 因此,`match.group(1)`是`a`,`match.group(2)`是`b`,`match.group(3)`是`c`,同时`match.group('name')`也是`b`。 ### 性能考虑 引用[4]提到,非捕获组可以提高性能,因为不需要保存匹配结果。在不需要获取子组内容时,尽量使用非捕获组。 ### 总结 Python正则表达式的命名捕获组通过`(?P<name>pattern)`语法实现,提供了通过名称访问匹配文本的能力,增强了可读性和可维护性。同时,非捕获组`(?:pattern)`在仅用于结构分组而不需要保存匹配结果时,可以提高性能。 如果您有具体的字符串匹配需求,可以尝试使用命名捕获组来设计正则表达式。 §§相关问题§§ 1. 如何在Python正则表达式中使用非捕获组? 2. 命名捕获组和普通捕获组在性能上有何差异? 3. 如何避免正则表达式中命名捕获组的名称冲突? 4. 除了`re.search`,命名捕获组在`re.findall`或`re.finditer`中如何使用?</think>### Python 正则表达式命名捕获组 `?P<name>` 使用方法 命名捕获组是正则表达式中用于**为匹配的子字符串命名**的功能,通过语法 `(?P<name>pattern)` 实现。它允许通过名称(而非数字索引)访问匹配结果,提高代码可读性和可维护性。 #### 核心语法 ```regex (?P<name>pattern) ``` - **`?P<name>`**:定义捕获组名称(`name` 需符合变量命名规则) - **`pattern`**:该组匹配正则表达式 --- ### 使用步骤(附示例代码) #### 1. 定义命名捕获组 ```python import re # 示例:从日期字符串提取年月日 pattern = r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})' text = "2024-08-26" ``` #### 2. 匹配并获取结果 通过 `match.group('name')` 或 `match.groupdict()` 访问命名组: ```python match = re.search(pattern, text) if match: # 通过名称获取 print(match.group('year')) # 输出: 2024 print(match.group('month')) # 输出: 08 # 获取所有命名组的字典 print(match.groupdict()) # 输出: {'year': '2024', 'month': '08', 'day': '26'} ``` --- ### 关键特性 1. **与数字索引共存** 命名组仍保留数字索引,可通过 `match.group(1)` 访问: ```python print(match.group(1)) # 等价于 match.group('year') → "2024" ``` 2. **在 `re.sub()` 中的引用** 替换时使用 `\g<name>` 引用命名组: ```python new_text = re.sub(pattern, r'\g<month>/\g<day>/\g<year>', text) print(new_text) # 输出: 08/26/2024 ``` 3. **与普通捕获组混合使用** 命名组和普通组 `(pattern)` 可共存,数字索引按左括号顺序分配: ```python pattern = r'(?P<name>\w+):(\d+)' # 命名组索引=1, 普通组索引=2 ``` --- ### 对比非捕获组 `(?:)` | 特性 | 命名捕获组 `(?P<name>pattern)` | 非捕获组 `(?:pattern)` | |--------------|--------------------------------|------------------------| | **匹配保存** | 保存到 `group()` | 不保存 | | **访问方式** | 名称或数字索引 | 不可访问 | | **性能** | 较慢(需存储结果) | 更快(无存储开销) | | **适用场景** | 需提取子字符串时 | 仅用于结构分组时 | > 非捕获组示例:`r'(?:http|https)://(?P<domain>[^/]+)'` 忽略协议类型的保存[^4] --- ### 实际应用场景 1. **结构化数据提取**(日志、日期等) ```python log_pattern = r'\[(?P<time>\d{2}:\d{2})\] (?P<level>ERROR|INFO): (?P<msg>.+)' ``` 2. **复杂文本替换** ```python re.sub(r'(?P<first>\w+)\s+(?P<last>\w+)', r'\g<last>, \g<first>', "John Doe") ``` 3. **提高正则可读性** 通过名称(而非 `group(3)`)明确匹配内容的含义。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值