使用规则
字符 | 含义 |
---|---|
普通字符 | 只与自己匹配,作为字面字符 |
通配符(.) | 与除换行符(\r、\n)外的任何单个字符匹配。 Python的re.DOTALL/re.S模式 或 notepad++的“.匹配新行”模式,通配符可以与换行符匹配,Pycharm不支持。 |
字符集 (-) | 匹配范围内的单个字符,例如[pj]、[a-z]、[a-zA-Z0-9] |
排除字符集(^) | 例如[^abc]与除a、b、c外的其他任何单个字符都匹配 |
二选一(|) | python|perl 匹配 python或python |
子模式(小括号) | 例如p(ython|erl) |
可选模式(?) | 放在子模式后面,将其指定为可选的。例如abc?与ab和abc匹配。 ?默认为贪婪模式,即尽量匹配更长的字符串,从后面添加?可以变为??非贪婪模式 |
重复模式(*+{ }) | (pattern)*:pattern可重复0、1或多次。 (pattern)+:pattern可重复1或多次。 (pattern){m, n}:模式可重复m~n次,也可以是{n}、{m, }。 * + {m, n} {m, }默认为贪婪模式,即尽量匹配更长的字符串,从后面添加?可以变为*? +? {m, n}? {m, }?非贪婪模式 |
字符串开头(^)和结尾($) | 例如(^http)与http开头的字符串匹配,(org$)与org结尾的字符串匹配 python默认为单行模式,即^匹配第一行的开头,$匹配最后一行的结尾, re.M或re.MULTILINE(多行模式)^$分别可以匹配每一行文本的开头和结尾。例如在 ‘foo1\nfoo2\n’ 或 ‘foo1\nfoo2’ 中搜索 foo.$,通常匹配 ‘foo2’,但在 MULTILINE 模式下可以匹配到 ‘foo1’。 例如在默认单行模式下’ddddd\nabbbc’搜索’^a.*c$'失败,但多行模式下搜索结果为(6, 11)。 pycharm和notepad++默认且只能是多行模式 |
\d | 匹配所有的十进制数字 |
\D | 匹配所有的非十进制数字(包括换行符) |
\s | 匹配所有的空白字符(空格、TAB等) |
\S | 匹配所有的非空白字符(包括换行符) |
\w | 匹配所有的字母、汉字、数字、下划线 |
\W | 匹配所有的非字母、汉字、数字、下划线(包括换行符) |
\b | (根据例子理解)匹配在单词开始或结尾位置的空字符串。r’\bfoo\b’匹配’foo’, ‘foo.’, ‘(foo)’, ‘bar foo baz’但不匹配’foobar’, ‘foo3’。 |
\B | (根据例子理解) 匹配不在单词开始或结尾位置的空字符串。r’py\B’匹配’python’, ‘py3’, ‘py2’但不匹配’py’, ‘py.’, ‘py!’。 |
注意:
- 匹配特殊字符时,需要使用\进行转义。例如要匹配字符串中’python.org’,因为.是特殊字符(通配符),所以要对其进行转义,表达式应该为’python\\.org’(这里包括两层转义:解释器执行的转义和模块re执行的转义,因为在字符串中\为转义字符,所以\\才表示一个真正的\),也可以使用原始字符串r’python\.org’
- (重要)贪婪模式 vs. 懒惰模式(易错)
经常看到,贪婪模式(默认)寻求最长匹配,懒惰模式寻求最短匹配。直观上,abbb查询ab?? 结果应是a,aaab查询标记a??b结果应是b,但aaab查询标记a??b的结果实际是ab,即这样理解是错误的。
实际上应该这样理解,懒惰模式一旦找到符合的匹配即作为查询结果返回,贪婪模式(默认)找到符合的匹配后,不断向后添加字符至匹配失败,失败前一步的字符串作为查询结果返回。为了方便理解,可以认为匹配过程是将子串string[s, e](s从0到n-1,e从s+1到n)与查询串pattern的(1+n)*n/2次比较过程。
Notepad++
windows notepad++换行符是\r\n
“Ctrl+F”,弹出查找窗口,如下图所示
匹配大小写:勾选时匹配大小写
.匹配新行:不勾选时通配符(.)不能匹配(\r、\n),勾选时通配符(.)能匹配(\r、\n)
PyCharm
匹配大小写:勾选时匹配大小写
Python
re模块官方API
主串:被查询的长字符串;模式串:作为查询关键字的短字符串
compile
# 使用模式串pattern(str类型)构建正则表达式对象
re.compile(pattern, flags=0)
# 常用flag,可以用“|”将多个flag连接起来
# 忽略大小写
re.I
re.IGNORECASE
# 多行模式
re.M
re.MULTILINE
# .匹配新行
re.S
re.DOTALL
search
# 返回第一个位置的 匹配对象(re.Match object) 或 None
# 两种调用方式的函数原型
re.search(pattern, string, flags=0)
Pattern.search(string[, pos[, endpos]])
# 调用方式1(模式串str,主串str,flags)
re.search(pattern, string, flags)
# 调用方式2(模式串str,flags;主串str,开始位置int,结束位置int)
prog = re.compile(pattern, flags)
prog.search(string, pos ,endpos)
# 例如
result = re.search('345', '123456')
print(result.start(), result.end())
# 2 5
prog = re.compile('345')
result = prog.search('123456')
print(result.start(), result.end())
# 2 5
split
# 分割字符串
re.split(pattern, string, maxsplit=0, flags=0)
Pattern.split(string, maxsplit=0)
>>> re.split(r'\W+', 'Words, words, words.')
['Words', 'words', 'words', '']
# 添加括号后,用来分割的字符也将作为返回值
>>> re.split(r'(\W+)', 'Words, words, words.')
['Words', ', ', 'words', ', ', 'words', '.', '']
>>> re.split(r'\W+', 'Words, words, words.', 1)
['Words', 'words, words.']
>>> re.split('[a-f]+', '0a3B9', flags=re.IGNORECASE)
['0', '3', '9']
>>> re.split(r'(\W+)', '...words, words...')
['', '...', 'words', ', ', 'words', '...', '']
>>> re.split(r'\b', 'Words, words, words.')
['', 'Words', ', ', 'words', ', ', 'words', '.']
# 注意,*是可以匹配到空字符串的(+不能),所以此处的r'\W*'成功匹配8次(包含6次空字符串匹配)
>>> re.split(r'\W*', '...words...')
['', '', 'w', 'o', 'r', 'd', 's', '', '']
>>> re.split(r'(\W*)', '...words...')
['', '...', '', '', 'w', '', 'o', '', 'r', '', 'd', '', 's', '...', '', '', '']
# r'\w*'成功匹配8次(包含7次空字符串匹配)
>>> re.split(r'\w*', '...words...')
['', '.', '.', '.', '', '.', '.', '.', '']
>>> re.split(r'(\w*)', '...words...')
['', '', '.', '', '.', '', '.', 'words', '', '', '.', '', '.', '', '.', '', '']
findall
# 返回pattern在string中所有非重叠匹配的字符串列表
re.findall(pattern, string, flags=0)
Pattern.findall(string[, pos[, endpos]])
# 例如
>>> re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest')
['foot', 'fell', 'fastest']
Java
String
// obj和regex严格的完全匹配
public boolean matches(String regex);
public String replaceFirst(String regex, String replacement);
public String replaceAll(String regex, String replacement);
public String[] split(String regex, int limit);
public String[] split(String regex);
Pattern
无构造函数,只能通过compile构造Pattern对象
// 静态方法
public static Pattern compile(String regex);
// flags: CASE_INSENSITIVE, MULTILINE, DOTALL, UNICODE_CASE, CANON_EQ, UNIX_LINES, LITERAL, UNICODE_CHARACTER_CLASS and COMMENTS
public static Pattern compile(String regex, int flags);
// regex和input严格的完全匹配
// CharSequence: 接口,常见实现类有:String StringBuffer StringBuilder CharBuffer
public static boolean matches(String regex, CharSequence input);
// 实例方法
// Predicate<T>:函数式接口,有boolean test(T t)方法
// obj和t严格的完全匹配
public Predicate<String> asMatchPredicate();
// obj出现在t中
public Predicate<String> asPredicate();
public String[] split(CharSequence input);
public String[] split(CharSequence input, int limit);
public Stream<String> splitAsStream(final CharSequence input);
// 生成Matcher对象
public Matcher matcher(CharSequence input);
Matcher
无构造函数,只能通过Pattern类的matcher方法构造Matcher对象
// 常用实例方法
// 查找str中与Patter对象匹配的下一个区间
// 存在返回true,否则返回false
public boolean find()
// 当前区间起始值
public int start()
// 当前区间终止值
public int end()
// 重置Matcher
public Matcher reset()
示例
public class Main {
public static void main(String[] args) {
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher("aaa54bb666");
while (matcher.find()) {
System.out.println(String.format("(%d, %d)", matcher.start(), matcher.end()));
}
// (3, 5)
// (7, 10)
}
}