day03_正则表达式

1、数据分类

  1. 数据的分类

    ​ 定义:数据以行为单位,每一个数据表示一个实体的信息。每一行数据的属性都是一样的。

    ​ 常见的结构化数据为关系型数据库存储数据。

  2. 半结构化数据

    ​ 定义:结构化数据的另一种形式,但是并不符合关系型数据的特点,不能用关系型模型来描述,但是 这种数据包含相关标记,有用来分隔语义元素以及字段进行分层的描述。因此也被称为自描述结构。

  3. 非结构化数据

    ​ 定义:没有固定的结构的数据。
    ​ 常见的非结构化数据有:文档,图片,音频,视频等。
    ​ 一般非结构化数据,都是通过整体存储他们二进制格式的数据来进行保存。

2、json数据

2.1、json语言概念

​ js中的语言,用来以【字符串】的形式来保存js中的对象和数组的一种技术。

2.2、js中对象和数组的格式
  • js的数组:var names = ["zs", "ls", "ww"]
  • js对象:varuser = {name: "zs", age: 18, height: 170}
2.3、json数据解析
  • json.loads('json字符串') 将json数据转成python对象(dict, list)
  • json.dumps('python对象') 将python对象转成json字符串
2.4、json数据的优势
  • 数据量很小

  • 传输效率高

3、正则表达式

3.1、正则表达式的定义

​ 正则表达式,又称规则表达式,通常被用来检索、替换那些符合某个模式(规则)的文本。

​ 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组

​ 合,组成一个"规则字符串",这个"规则字符串"用来表达对字符串的一种过滤逻辑。

3.2、正则表达式的作用
  • 给定的字符串是否符合正则表达式的过滤逻辑("匹配");
  • 通过正则表达式,从文本字符串中获取我们想要的特定部分("过滤")。
3.3、正则表达式匹配规则

(1)常用的元字符:

语法 说明 表达式实例 完整匹配的字符串
\d 0-9之间的任意数字 a\dc a2c
\D 除了\d a\Dc abc
\w 数字、字母、下划线中任意一种 a\wc abc
\W 除了\w a\Wc a%c
\n 换行
\s 空白或空格 a\sc a c
. 除了\n任意字符
\. \ 转义让.代表自身
\b 单词的边界
^ 开始 ^abc abc
$ 结束 abc$ abc
[\u4e00-\u9fa5] 中文

(3)量词:

语法 说明 表达式实例 完整匹配的字符串
匹配前一个字符0或1次 abc? ab, abc
+ 匹配前一个字符1或多次 abc+ abc, abccc
* 匹配前一个字符0或多次 abc* ab, abccc
{n} 匹配前一个字符n次 ab{2}c abbc
{n,} 匹配前一个字符n-多次 ab{2,}c abbc, abbbbc
{n,m} 匹配前一个字符n-m次 ab{1,2}c abc, abbc

(3)量词:

语法 说明 表达式实例 完整匹配的字符串
| 或者,由于优先级比较低,经常和小括号一起使用 abc|cd
[0-9] 0-9之间任意一个,相当于\d
[xyz] x或y或z
[\d\s] 数字或空白中的一个
[.] 体表.本身
[+-] +-中的一个
[^xyz] 除了x,y,z任意一个字符
3.4、正则表达式的使用步骤
  • 使用 compile() 函数将正则表达式的字符串形式编译为一个 Pattern 对象
  • 通过 Pattern 对象提供的一系列方法对文本进行匹配查找,获得匹配结果,一个 Match 对象。
  • 最后使用 Match 对象提供的属性和方法获得信息,根据需要进行其他的操作
3.5、compile 函数

compile 函数用于编译正则表达式,生成一个 Pattern 对象,它的一般使用形式如下:

import re

# 将正则表达式编译成 Pattern 对象
pattern = re.compile(r'\d+')

Pattern 对象的一些常用方法主要有:

  • match 方法:从起始位置开始查找,一次匹配
  • search 方法:从任何位置开始查找,一次匹配
  • findall 方法:全部匹配,返回列表
  • finditer 方法:全部匹配,返回迭代器
  • split 方法:分割字符串,返回列表
  • sub 方法:替换
3.6、pattern对象中方法
  • 3.6.1、match方法

    默认从开始位置开始匹配,只匹配一次, 只要找到了一个匹配的结果就返回,而不是查找所有匹配的结果。 它的一般使用形式如下:

    match(string[, start, end])

    其中,string 是待匹配的字符串,start 和 end 是可选参数,指定字符串的起始和终点位置,默认值分别是 0 和 len (字符串长度)。因此,当你不指定 start 和 end 时,match 方法默认匹配字符串的头部。

    当匹配成功时,返回一个 Match 对象,如果没有匹配上,则返回 None。

    >>> import re
    >>> pattern = re.compile(r'\d+')  # 用于匹配至少一个数字
    
    >>> m = pattern.match('one12twothree34four')  # 从头部开始查找,没有匹配
    >>> print (m)
    None
    
    >>> m = pattern.match('one12twothree34four', 2, 10) # 从'e'的位置开始匹配,没有匹配到
    >>> print (m)
    None
    
    >>> m = pattern.match('one12twothree34four', 3, 10) # 从'1'的位置开始匹配,正好匹配到
    >>> print (m)                                         # 返回一个 Match 对象
    <_sre.SRE_Match object at 0x10a42aac0>
    
    >>> m.group(0)   # 可省略 0
    '12'
    >>> m.start(0)   # 可省略 0
    3
    >>> m.end(0)     # 可省略 0
    5
    >>> m.span(0)    # 可省略 0
    (3, 5)
    

    匹配成功时返回一个match对象,其中:

    • group() 方法用于获得一个或多个分组匹配的字符串,当要获得整个匹配的子串时,可直接使用 group() 或 group(0);
    • start( ) 方法用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为 0;
    • end( ) 方法用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认值为 0;
    • span( ) 方法返回 (start(group), end(group))。
    
    >>> import re
    >>> pattern = re.compile(r'([a-z]+) ([a-z]+)', re.I)  # re.I 表示忽略大小写
    >>> m = pattern.match('Hello World Wide Web')
    
    >>> print (m)     # 匹配成功,返回一个 Match 对象
    <_sre.SRE_Match object at 0x10bea83e8>
    
    >>> m.group(0)  # 返回匹配成功的整个子串
    'Hello World'
    
    >>> m.span(0)   # 返回匹配成功的整个子串的索引
    (0, 11)
    
    >>> m.group(1)  # 返回第一个分组匹配成功的子串
    'Hello'
    
    >>> m.span(1)   # 返回第一个分组匹配成功的子串的索引
    (0, 5)
    
    >>> m.group(2)  # 返回第二个分组匹配成功的子串
    'World'
    
    >>> m.span(2)   # 返回第二个分组匹配成功的子串
    (6, 11)
    
    >>> m.groups()  # 等价于 (m.group(1), m.group(2), ...)
    ('Hello', 'World')
    
    >>> m.group(3)   # 不存在第三个分组
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    IndexError: no such group
  • 3.6.2、search方法

    用于查找字符串的任何位置,它也是一次匹配,只要找到了一个匹配的结果就返回,而不是查找所有匹配的结果,它的一般使用形式如下:

    search(string[, start, end])

    其中,string 是待匹配的字符串,start 和 end 是可选参数,指定字符串的起始和终点位置,默认值分别是 0 和 len (字符串长度)。

    当匹配成功时,返回一个 Match 对象,如果没有匹配上,则返回 None。

    >>> import re
    >>> pattern = re.compile('\d+')
    >>> m = pattern.search('one12twothree34four')  # 这里如果使用 match 方法则不匹配
    >>> m
    <_sre.SRE_Match object at 0x10cc03ac0>
    >>> m.group()
    '12'
    >>> m = pattern.search('one12twothree34four', 10, 30)  # 指定字符串区间
    >>> m
    <_sre.SRE_Match object at 0x10cc03b28>
    >>> m.group()
    '34'
    >>> m.span()
    (13, 15)

    再来看一个例子:

    import re
    # 将正则表达式编译成 Pattern 对象
    pattern = re.compile(r'\d+')
    # 使用 search() 查找匹配的子串,不存在匹配的子串时将返回 None
    # 这里使用 match() 无法成功匹配
    m = pattern.search('hello 123456 789')
    if m:
        # 使用 Match 获得分组信息
        print ('matching string:',m.group())
        # 起始位置和结束位置
        print ('position:',m.span())

    执行结果:

    matching string: 123456
    position: (6, 12)
  • 3.6.3、findall方法

    默认从头开始匹配,搜索整个字符串,获取所有匹配的结果。它的一般使用形式如下:

    findall(string[, start, end])

    其中,string 是待匹配的字符串,start 和 end 是可选参数,指定字符串的起始和终点位置,默认值分别是 0 和 len (字符串长度)。

    findall 以列表形式返回全部能匹配的子串,如果没有匹配,则返回一个空列表。

    看看例子:

    import re
    pattern = re.compile(r'\d+')   # 查找数字
    
    result1 = pattern.findall('hello 123456 789')
    result2 = pattern.findall('one1two2three3four4', 0, 10)
    
    print (result1)
    print (result2)

    执行结果:

    ['123456', '789']
    ['1', '2']

    再先看一个例子:

    import re
    
    pattern = re.compile(r'\d+\.\d*')
    
    #通过partten.findall()方法就能够全部匹配到我们得到的字符串
    result = pattern.findall("123.141593, 'bigcat', 232312, 3.15")
    
    #findall 以 列表形式 返回全部能匹配的子串给result
    for item in result:
        print (item)

    运行结果:

    123.141593
    3.15
  • 3.6.4、finditer方法

    finditer 方法的行为跟 findall 的行为类似,也是搜索整个字符串,获得所有匹配的结果。但它返回一个 顺序访问每一个匹配结果(Match 对象)的迭代器。

    看看例子:

    import re
    
    
    pattern = re.compile(r'\d+')
    
    ret1_iter = pattern.finditer('hello 123456 789')
    ret2_iter = pattern.finditer('one1two2three3four4', 0, 10)
    
    print(type(ret1_iter))
    print(type(ret1_iter))
    
    print('----ret1----')
    for m1 in ret1_iter:
        # print(m1)  # m1是一个对象
        print('matching string:{},position:{}'.format(m1.group(), m1.span()))
    
    print('----ret2----')
    for m2 in ret2_iter:
        # print(m2)  # m2是一个对象
        print('matching string:{},position:{}'.format(m2.group(), m2.span()))

    执行结果:

    <class 'callable_iterator'>
    <class 'callable_iterator'>
    ----ret1----
    matching string:123456,position:(6, 12)
    matching string:789,position:(13, 16)
    ----ret2----
    matching string:1,position:(3, 4)
    matching string:2,position:(7, 8)
  • 3.6.5、split方法

    split 方法按照能够匹配的子串将字符串分割后返回列表,它的使用形式如下:

    split(string[, count])

    其中,count 用于指定最大分割次数,不指定将全部分割。

    看看例子

    import re
    
    pattern = re.compile(r'[\s\,\;]+')
    ret = pattern.split('a,b;;c   d')
    print(ret)

    执行结果:

    ['a', 'b', 'c', 'd']
  • 3.6.6、sub方法

    sub 方法用于替换。它的使用形式如下:

    sub(repl, string[, count])

    其中,repl 可以是字符串也可以是一个函数:

    • 如果 repl 是字符串,则会使用 repl 去替换字符串每一个匹配的子串,并返回替换后的字符串,另外,repl 还可以使用 id 的形式来引用分组,但不能使用编号 0;
    • 如果 repl 是函数,这个方法应当只接受一个参数(Match 对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。
    • count 用于指定最多替换次数,不指定时全部替换。

    看看例子:

    import re
    
    pattern = re.compile(r'(\w+) (\w+)')
    s = 'hello 123, hello 456'
    print(pattern.sub('hello world', s)) # 使用 'hello world' 替换 'hello 123' 和 'hello 456'
    print(pattern.sub(r'\1 \2', s))  # 引用分组
    
    print('-' * 50)
    def fun(m):
        print(m)  # 传递参数必须为一个Match对象
        return 'hi' + ' ' + m.group(2)  # group(0)表示本身,group(1)表示hello,group(2)表示后面的数字
    
    print(pattern.sub(fun, s))  # 每次sub的结果传递给fun
    print(pattern.sub(fun, s, 1))  # 只替换一次

    执行结果:

    hello world, hello world
    hello 123, hello 456
    ------------------------------------------------------------
    <_sre.SRE_Match object; span=(0, 9), match='hello 123'>
    <_sre.SRE_Match object; span=(11, 20), match='hello 456'>
    hi 123, hi 456
    <_sre.SRE_Match object; span=(0, 9), match='hello 123'>
    hi 123, hello 456
3.7、匹配中文

中文的 unicode 编码范围 主要在 [u4e00-u9fa5] , 这里说主要是因为这个范围并不完整,比如没有包括全角(中文)标点,不过,在大部分情况下,应该是够用的。

假设现在想把字符串 title = u'你好,hello,世界' 中的中文提取出来,可以这么做:

import re

title = '你好,hello,世界'
pattern = re.compile(r'[\u4e00-\u9fa5]+')
result = pattern.findall(title)

print (result)

正则表达式前面加上了两个前缀 ur,其中 r 表示使用原始字符串,u 表示是 unicode 字符串。

3.8、贪婪模式与非贪婪模式
  • 婪模式:在整个表达式匹配成功的前提下,尽可能多的匹配 ( * );

  • 非贪婪模式:在整个表达式匹配成功的前提下,尽可能少的匹配 ( ? );

  • Python里数量词默认是贪婪的。

例子一:源字符串:abbbc

  • 使用贪婪的数量词的正则表达式 ab* ,匹配结果: abbb。

* 决定了尽可能多匹配 b,所以a后面所有的 b 都出现了。

  • 使用非贪婪的数量词的正则表达式ab*?,匹配结果: a。

即使前面有 *,但是 ? 决定了尽可能少匹配 b,所以没有 b。

例子二:源字符串:aa<div>test1</div>bb<div>test2</div>cc

  • 使用贪婪的数量词的正则表达式: <div>.*</div>
  • 匹配结果: <div>test1</div>bb<div>test2</div>

这里采用的是贪婪模式。在匹配到第一个</div>时已经可以使整个表达式匹配成功,但是由于采用的是贪婪模式,所以仍然要向右尝试匹配,查看是否还有更长的可以成功匹配的子串。匹配到第二个</div>后,向右再没有可以成功匹配的子串,匹配结束,匹配结果为<div>test1</div>bb<div>test2</div>


  • 使用非贪婪的数量词的正则表达式 : <div>.*?</div>
  • 匹配结果:<div>test1</div>

正则表达式二采用的是非贪婪模式,在匹配到第一个</div>时使整个表达式匹配成功,由于采用的是非贪婪模式,所以结束匹配,不再向右尝试,匹配结果为<div>test1</div>

猜你喜欢

转载自www.cnblogs.com/xiaoywu/p/11967524.html