正则表达式高级

正则表达式高级
——《精通正则表达式》
+Java/Go/Python官方文档
+多年经验
+实验结果
知识整理

[TOC]

第3章 正则表达式的特性和流派概览

常用的元字符和特性 102

基本语法
https://www.runoob.com/regexp/regexp-metachar.html

量词

  • {n} {n,} {n,m}

  • *{0,}

  • +{1,}

  • ?{0,1}

  • 量词默认匹配优先(贪婪,越多越好)

  • 后面加?则忽略优先(非贪婪,越少越好)

  • 后面加+则占有优先(类似固化分组, golang不支持),
    匹配了就不会还回去,例如
    .*+c匹配abc
    .*会匹配优先地匹配到abc三个字符,
    如果没有+时发现匹配失败就会回溯到.*匹配两个的情况,这时匹配成功;
    而有+就占有不还回去了,匹配失败。

分组与捕获

"abc".replaceAll("a(.*)c", "s$1"); // sb
"b2b".replaceAll("(.*)2\\1", "s$1"); // sb

"b2b".replaceAll("(?<a>.*)2\\k<a>", "s${a}"); // sb

Pattern p = Pattern.compile("a(?<a>.*)c");
Matcher m = p.matcher("abc");
while (m.find()) {
    System.out.println(m.group(1)); // b
    System.out.println(m.group("a")); // b
}

反向引用组编号n为0代表全部,同m.group()

  • 分组并捕获(...)
  • 正则反向引用(Java Python)\n(golang貌似未提供)
  • 字符反向引用(Java golang)$n
  • 字符反向引用(Python)\n \g<n>
  • 命名捕获(Java)(?<name>...)
  • 正则反向引用(Java)\k<name>
  • 字符反向引用(Java golang)${name}
  • 字符反向引用(golang)$name
  • 命名捕获(Python golang)(?P<name>...)
  • 正则反向引用(Python)(?P=name)
  • 字符反向引用(Python)\g<name>
  • 多选结构...|...
  • 仅分组不捕获(?:...)
  • 固化分组(golang不支持)(?>...)
  • 注释(宽松排列时 golang不支持)# ...

Java不支持:

  • 条件(Python)(?(n/name)...|...)
  • 代码条件(?... ...|...)
  • 嵌入式注释(?#...)
  • 嵌入式代码(?{...})
  • 动态表达式(??{...})

边界

锚点:

  • 行始^
  • 文始\A \G
  • 行末$
  • 文末\Z \z
  • 单词边界\b
  • 非单词边界\B

环视结构(零长度断言,golang不支持):

  • 顺序环视
    • 左边是A:(?<=A)
    • 左边不是A:(?<!A)
  • 逆序环视
    • 右边是A:(?=A)
    • 右边不是A:(?!A)
"abc".replaceAll("(?<=a)b(?=c)", ""); // ac

查找时用捕获比环视更容易阅读

注释与模式

通用常用

  • (?i)不区分大小写CASE_INSENSITIVE(Java 轻微影响性能)
  • (?m)多行模式(^$匹配整个字符串的头尾)MULTILINE
  • (?s)点号通配模式(.匹配任意字符)DOTALL

Java

  • (?idmsuxU-idmsuxU)
  • (?idmsux-idmsux:X)
  • (?u)Unicode不区分大小写UNICODE_CASE(影响性能)
  • (?x)宽松排列和注释(忽略空白和#后的内容)COMMENTS
  • (?d)Unix行模式(只有\n)UNIX_LINES
  • Unicode按规则等价CANON_EQ(影响性能)
  • \Q...\E不使用元字符和转义序列LITERAL(1.5+)
  • (?U)启用预定义和POSIX字符类UNICODE_CHARACTER_CLASS(1.7+,影响性能)

Python

  • (?aiLmsux-imsx:…)
  • (?a)仅ASCII
  • (?L)语言依赖

其他

  • (?o)编译一次(提升性能,Perl)
  • (?U)忽略优先模式交换x*x*?...的含义(golang)

也可以这样用:(?-i) (?i:...) (?-i:...)

Pattern p = Pattern.compile("a(?i)b(?-i)c(?i:d)");
Matcher m = p.matcher("aBcD");

Pattern p = Pattern.compile("a", Pattern.CASE_INSENSITIVE);

字符组

  • . 换行符外任意字符
  • [...]字符组(元字符不需转义)
    [a-z]匹配小写字母
  • [^...]不包含

Perl字符族:

  • \d[0-9]
  • \D[^0-9]
  • \w[A-Za-z0-9_]
  • \W[^A-Za-z0-9_]
  • \s[ \t\n\v\f\r]
  • \S[^ \t\n\v\f\r]
  • \C字节
  • \XUnicode

ASCII字符族(来自golang):
[[:alnum:]]字母数字同[0-9A-Za-z]
[[:alpha:]]字母同[A-Za-z]
[[:ascii:]]ASCII同[\x00-\x7F]
[[:blank:]]空白[\t ]
[[:cntrl:]]控制[\x00-\x1F\x7F]
[[:digit:]]数字[0-9]
[[:graph:]]图形[!-~] == [A-Za-z0-9!"#$%&'()*+,\-./:;<=>?@[\\\]^_{|}~][[:lower:]]小写[a-z][[:print:]]可打印[ -~] == [ [:graph:]][[:punct:]]标点[!-/:-@[-{-~]
[[:space:]]空字符[\t\n\v\f\r ]
[[:upper:]]大写[A-Z]
[[:word:]]字符[0-9A-Za-z_]
[[:xdigit:]]十六进制[0-9A-Fa-f]

Unicode组:

  • \p{}Unicode 区块/属性/分类,如

java汉字

"Hi,你好!".replaceAll("[^\\p{javaIdeographic}]", ""); // 你好
Character.isIdeographic​(int codePoint) // CJKV(中文,日文,韩文和越南文)表意文字

https://docs.oracle.com/en/Java/Javase/12/docs/api/Java.base/Java/util/regex/Pattern.html

golang汉字

package main_test

import (
    "fmt"
    "regexp"
)

func ExampleFindAllString() {
    r := regexp.MustCompile(`[\p{Han}]+`) // 汉字
    split := r.FindAllString("你好,中国!", -1)
    for _, s := range split {
        println(s) // 不计入output
        fmt.Println(s)
    }

    // Output:
    // 你好
    // 中国
}

https://studygolang.com/static/pkgdoc/pkg/regexp.htm

https://godoc.org/regexp/syntax

https://godoc.org/regexp

python汉字

# coding=utf-8
import re
if __name__ == "__main__":
    print(re.findall(r'[\u4e00-\u9fa5]+', '你好,中国!'))

https://docs.Python.org/zh-cn/3/library/re.html#contents-of-module-re

字符

  • \a警报同\x09 \cI
  • \b退格同\x09 \cI
  • \e退出同\x09 \cI
  • \t制表同\x09 \cI
  • \n换行同\x0a \cJ
  • \v直表同\x0b \cK
  • \f分页同\x0c \cL
  • \r回车同\x0d \cM
  • \*
  • \07 \77 0377八进制(带0是Java特殊)
  • \xFF \uFFFF 十六进制
  • \x{10FFFF} 十六进制(golang)
  • \u00A9Unicode 版权符号
  • \Q...\E不使用元字符和转义序列
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351

推荐阅读更多精彩内容