Regular Expression 学习

没有使用Regex…之类的软件,准备先学习Py和C++的正则表达式类,然后用这两个语言来实现练习

Swift中的RegEx

主要参考onecat的SwifterTips

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct RegexHelper {
let regex: NSRegularExpression

init(_ pattern: String) throws {
try regex = NSRegularExpression(pattern: pattern,
options: .CaseInsensitive)
}

func match(input: String) -> Bool {
let matches = regex.matchesInString(input,
options: [],
range: NSMakeRange(0, input.utf16.count))
return matches.count > 0
}
}

C++的Regex库

First:

1
#include<regex>

Then:

1
2
3
4
5
string pattern("[^c]ei");
pattern = "[[:alpha:]]*" + pattern + "[[:alpha:]]*";
regex r(pattern);
smatch results;
string test_str = "receipt freind theif receive";

Last:

1
2
if (regex_search(test_str,results,r))
cout<< results.length()<<endl;

在C++ regex库中,对应四种操作:

  1. regex_match 匹配
  2. regex_search 寻找匹配的字符序列
  3. regex_replace 替换一个正则表达式
  4. regex_iterator 迭代适配器

Python 与正则表达式

First:

1
import re

Then:
编译我们的正则表达式,生成pattern对象

1
pattern = re.compile(r'........')

Last:
使用pattern对象的match函数来获取匹配结果

1
2
3
result = pattern.match('.......') # 要处理的字符串
if match:
print match.group()

关于Compile:

compile(str[,flag])可以有多个参数,第一个参数接受regular expression, 第二个参数是匹配模式,比如说控制大小写之类的。

  • re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
  • M(MULTILINE): 多行模式,改变’^’和’$’的行为(参见上图)
  • S(DOTALL): 点任意匹配模式,改变’.’的行为
  • L(LOCALE): 使预定字符类 \w \W \b \B \s \S 取决于当前区域设定
  • U(UNICODE): 使预定字符类 \w \W \b \B \s \S \d \D 取决于unicode定义的字符属性

关于Match

Match一次匹配的结果 相当于C++中的smatch类型。

1
2
3
4
5
6
7
8
9
# match.end(..) 返回每一个子表达式的结束位置 
print m.end(1),m.end(2)
# start(..) 返回每一个子表达式起始位置
print m.start(1)
# group(..) 就相当于C++中的smatch的数组,编号为0 则输出整个匹配字符串。
print m.group(1, 2)
# 按元组的形式打印出所有的子表达式
print m.groups()
......

关于Search:

search(string[, pos[, endpos]]) | re.search(pattern, string[, flags]):

SearchMatch 有差异。

search: 从string的pos下标处起尝试匹配pattern,如果pattern结束时仍可匹配,则返回一个Match对象;若无法匹配,则将pos加1后重新尝试匹配;直到pos=endpos时仍无法匹配则返回None。

match: 从string的pos下标处起尝试匹配pattern;如果pattern结束时仍可匹配,则返回一个Match对象;如果匹配过程中pattern无法匹配,或者匹配未结束就已到达endpos,则返回None。

pos与endpos:
pos:文本中正则表达式开始搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。
endpos:文本中正则表达式结束搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
pattern = re.compile(r'hello', re.I)
match = pattern.search("WorldHellohelloworldHELLOWORLD")
if match:
print match.endpos
print match.pos
# 输出:
# 30
# 5
# 如果是match
match = pattern.match("WorldHellohelloworldHELLOWORLD")
if match:
print match.endpos
print match.pos
# 不会有任何输出

上述原因: 对于match,初始pos是0,而从pos开始进行匹配,到结束时,都没有成功匹配,则返回None。 而search会对pos进行修改来匹配.

关于findall:

findall(string[, pos[, endpos]]) | re.findall(pattern, string[, flags]):

1
2
3
4
5
6
pattern = re.compile(r'hello', re.I)
match = pattern.findall("World Hello hello world HELLO WORLD")
if match:
print match
# 输出:
['Hello', 'hello', 'HELLO']

搜索string,以列表形式返回全部能匹配的子串。

关于split:

split(string[, maxsplit]) | re.split(pattern, string[, maxsplit]):

按照能够匹配的子串将string分割后返回列表。maxsplit用于指定最大分割次数,不指定将全部分割。

1
2
3
4
5
6
pattern = re.compile(r'\.')
match = pattern.split("we.ed.edse.es")
if match:
print match
# 输出:
['we', 'ed', 'edse', 'es']

finditer:

finditer(string[, pos[, endpos]]) | re.finditer(pattern, string[, flags]):

搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。

sub:

sub(repl, string[, count]) | re.sub(pattern, repl, string[, count]):

使用repl替换string中每一个匹配的子串后返回替换后的字符串。
当repl是一个字符串时,可以使用\id或\g、\g引用分组,但不能使用编号0。
当repl是一个方法时,这个方法应当只接受一个参数(Match对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。
count用于指定最多替换次数,不指定时全部替换。

正则表达式:

匹配位置:

  1. ^ $ \b
    \bStr 匹配由str开头的单词 \b也可以匹配结尾 但不配空格标点符号换行符
    ^a 匹配由a开头的行
  2. 常用元字符

    • ^ 行开始位置
    • $ 行结束位置
    • \b 单词的开始与结束位置
    • . 匹配换行符外任意的字符
    • \w 匹配单词字符(字母,数字,下画线,汉字)
    • \W 匹配任何非单词字符(空格,制表符,换行符)
    • \s 匹配任意的空白字符,如空格,制表符,换行符,中文全角空格,就相当于 \W
    • \S 与\w 相似
    • \d 匹配任意的数字
    • \D 匹配任意的非数字

      Demo:

1
2
3
4
e_pattern = re.compile(r'\ba\w\s\w\D\d')
result = e_pattern.findall("a_ aw10 aa aaa")
if result:
print result
  1. 文字匹配:

    [...]: 如: [abcde]匹配a、b、c、d、e字符 [1234567890]:匹配所有数字.

    • [0-9] : 所有数字
    • [a-z] : 所有小写字母
    • [A-z] : 所有大写字母
    • [-a] : 匹配a或者-
    • [^a] : 匹配除a外的字符
    • \W = [^0-9a-zA-Z] 同样 \w = [0-9A-Za-z]
    • \p{name} : 匹配{name}指定的命名字符之内的任何字符
    • \P{name} : 与\p{name}相反
  1. 字符转义:
1
2
3
4
. : \.
* : \*
\ : \\
www.google.com: www\.google\.com
  1. 限定符:

    • {n} : 重复n次
    • {n,} : 至少重复n次
    • {n,m} : 至少n次之多m次
      • 重复至少0次 同 {0,}
      • 至少1次 同 {1,}
    • ? 重复 0 次或 1 次,相当于可选
    • {n,}? : 尽可能少重复,但至少n次

      ?尽量少重复

Demo:

1
2
3
4
l_pattern = re.compile(r'\bad{3}\d+\b')
result = l_pattern.findall("addd1212 addd12121211 add121 addd333dd")
if result:
print result
  1. 替换: |
    Jack|jack --> (J|j)ack
    (?(expression)yes|no) 要么与yes匹配要么与no匹配

Demo:

1
2
3
4
5
pattern = re.compile(r'\ba(yes|no)')
result = pattern.findall("ayes ano ayesno anoyes")
print result
output :
['yes', 'no', 'yes', 'no']

以上是正则表达式的基础部分,语言不同,可能会有部分改动。


HTML元素验证处理:

  • <.+> 匹配一切标签 包括这种:<a>> 这种事错误的
  • <[^>]+>
  • <[a-z][^>]*/> 一个标签的写法
  • <[a-z][^>]*> .*)</[a-z][^>]*> 就可以获取标签间的内容