• python3: 字符串和文本


    1. 分割字符串-使用多个界定符【re.split()】

    >>> line = 'asdf fjdk; afed, fjek,asdf, foo'
    >>> import re
    >>> re.split(r'[;,s]s*', line)
    ['asdf', 'fjdk', 'afed', 'fjek', 'asdf', 'foo']

    string 对象的 split() 方法只适应于非常简单的字符串分割情形, 它并不允许有多个分隔符或者是分隔符周围不确定的空格。 当你需要更加灵活的切割字符串的时候,最好使用 re.split() 方法

    >>> fields = re.split(r'(;|,|s)s*', line)
    >>> fields
    ['asdf', ' ', 'fjdk', ';', 'afed', ',', 'fjek', ',', 'asdf', ',', 'foo']
    >>>

    如果re.split()中使用了括号捕捉分组。如果使用了括号,那么被匹配的文本也将出现在结果列表中。

    如果不想保留分割字符串到结果列表中去,但仍然需要使用到括号来分组正则表达式的话, 确保你的分组是非捕获分组,形如 (?:...) 。比如

    >>> re.split(r'(?:,|;|s)s*', line)
    ['asdf', 'fjdk', 'afed', 'fjek', 'asdf', 'foo']
    >>>

    2. 字符串的开头匹配或结尾匹配【str.startwith()或 str.endwith()】

    如果想匹配多种可能时.只需将所有的匹配项放入到一个元组【tuple】中然后传给str.startwith()或 str.endwith()中

    >>> filenames
    [ 'Makefile', 'foo.c', 'bar.py', 'spam.c', 'spam.h' ]
    >>> [name for name in filenames if name.endswith(('.c', '.h')) ]
    ['foo.c', 'spam.c', 'spam.h']

    3. 用Shell通配符匹配字符串--【fnmath模块提供的两个函数--fnmatch()和fnmatchcase()】

     Unix Shell 中常用的通配符(比如 *.py , Dat[0-9]*.csv 等)去匹配文本字符串

    #  Shell通配符
    #
    #  ? 任意单个字符
    #  * 任意0个或多个字符
    #  [ ] 匹配方括号中的任意一个字符,如[abc] 则匹配abc中的一个
    #  [ - ] "-"代表范围,例如:[a-z] 则匹配任意一个小写字母; [0-9] 则匹配任意一个0-9之间的数据,但是注意[0-10]不可以,不能超过9
    #  [^] 逻辑非. 例如: [^0-9]匹配任意一个非数字字符
    >>> from fnmatch import fnmatch, fnmatchcase
    >>> fnmatch('foo.txt', '*.txt')
    True
    >>> fnmatch('foo.txt', '?oo.txt')
    True
    >>> fnmatch('Dat45.csv', 'Dat[0-9]*')
    True
    >>> names = ['Dat1.csv', 'Dat2.csv', 'config.ini', 'foo.py']
    >>> [name for name in names if fnmatch(name, 'Dat*.csv')]
    ['Dat1.csv', 'Dat2.csv']

    fnmatch() 函数使用底层操作系统的大小写敏感规则(不同的系统是不一样的)来匹配模式。比如:

    >>> # On OS X (Mac)
    >>> fnmatch('foo.txt', '*.TXT')
    False
    >>> # On Windows
    >>> fnmatch('foo.txt', '*.TXT')
    True
    >>>

    如果你对这个区别很在意,可以使用 fnmatchcase() 来代替。它完全使用你的模式大小写匹配。

    常用场景:在处理非文件名的字符串时候它们也是很有用的。文件名的匹配,最好使用 glob 模块

    addresses = [
        '5412 N CLARK ST',
        '1060 W ADDISON ST',
        '1039 W GRANVILLE AVE',
        '2122 N CLARK ST',
        '4802 N BROADWAY',
    ]
    你可以像这样写列表推导:
    
    >>> from fnmatch import fnmatchcase
    >>> [addr for addr in addresses if fnmatchcase(addr, '* ST')]
    ['5412 N CLARK ST', '1060 W ADDISON ST', '2122 N CLARK ST']
    >>> [addr for addr in addresses if fnmatchcase(addr, '54[0-9][0-9] *CLARK*')]
    ['5412 N CLARK ST']
    >>>

    4. 字符串匹配和搜索

    如果你想匹配的是字面字符串,那么你通常只需要调用基本字符串方法就行, 比如 str.find() , str.endswith() , str.startswith() 或者类似的方法:

     对于复杂的匹配需要使用正则表达式和 re 模块。 为了解释正则表达式的基本原理,假设你想匹配数字格式的日期字符串比如 11/27/2012 ,你可以这样做
     
    >>> text1 = '11/27/2012'
    >>> text2 = 'Nov 27, 2012'
    >>>
    >>> import re
    >>> # Simple matching: d+ means match one or more digits
    >>> if re.match(r'd+/d+/d+', text1):
    ... print('yes')
    ... else:
    ... print('no')
    ...
    yes
    >>> if re.match(r'd+/d+/d+', text2):
    ... print('yes')
    ... else:
    ... print('no')
    ...
    no
    >>>

    如果你想使用同一个模式去做多次匹配,你应该先将模式字符串预编译为模式对象。比如:

    >>> datepat = re.compile(r'd+/d+/d+')
    >>> if datepat.match(text1):
    ... print('yes')
    ... else:
    ... print('no')
    ...
    yes
    >>> if datepat.match(text2):
    ... print('yes')
    ... else:
    ... print('no')
    ...
    no
    >>>

    match() 总是从字符串开始去匹配,如果你想查找字符串任意部分的模式出现位置, 使用 findall() 方法去代替。比如:

    >>> text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
    >>> datepat.findall(text)
    ['11/27/2012', '3/13/2013']
    >>>

    在定义正则式的时候,通常会利用括号去捕获分组。

    #在定义正则式的时候,通常会利用括号去捕获分组
    #捕获分组可以使得后面的处理更加简单,因为可以分别将每个组的内容提取出来
    >>> datepat = re.compile(r'(d+)/(d+)/(d+)')
    >>> m = datepat.match('11/27/2012')
    >>> m
    <_sre.SRE_Match object at 0x1005d2750>
    >>> # Extract the contents of each group
    >>> m.group(0)
    '11/27/2012'
    >>> m.group(1)
    '11'
    >>> m.group(2)
    '27'
    >>> m.group(3)
    '2012'
    >>> m.groups()
    ('11', '27', '2012')
    >>> month, day, year = m.groups()
    >>>
    >>> # Find all matches (notice splitting into tuples)
    >>> text
    'Today is 11/27/2012. PyCon starts 3/13/2013.'
    >>> datepat.findall(text)
    [('11', '27', '2012'), ('3', '13', '2013')]
    >>> for month, day, year in datepat.findall(text):
    ... print('{}-{}-{}'.format(year, month, day))
    ...
    2012-11-27
    2013-3-13
    >>>

    正则表达式步骤: re.compile()编译正则表达式字符串, 然后使用match(), findall(), finditer()等方法

    如果你想精确匹配,确保你的正则表达式以$结尾,就像这么这样:

    >>> datepat = re.compile(r'(d+)/(d+)/(d+)$')
    >>> datepat.match('11/27/2012abcdef')
    >>> datepat.match('11/27/2012')
    <_sre.SRE_Match object at 0x1005d2750>
    >>>

    最后,如果你仅仅是做一次简单的文本匹配/搜索操作的话,可以略过编译部分,直接使用 re 模块级别的函数。比如:

    >>> re.findall(r'(d+)/(d+)/(d+)', text)
    [('11', '27', '2012'), ('3', '13', '2013')]
    >>>

    2.5 字符串搜索和替换

    对于简单的字面模式,直接使用 str.replace() 方法即可,比如:str.replace('tihuan_qian', 'tihuan_hou')

    复杂的模式,使用re模块的sub()函数。

    例: 11/27/2012 的日期字符串改成 2012-11-27

    >>> text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
    >>> import re
    >>> re.sub(r'(d+)/(d+)/(d+)', r'3-1-2', text)
    'Today is 2012-11-27. PyCon starts 2013-3-13.'
    >>>

    sub() 函数中的第一个参数是被匹配的模式,第二个参数是替换模式。反斜杠数字比如 3 指向前面模式的捕获组号。

     如果你打算用相同的模式做多次替换,考虑先编译它来提升性能。比如:
    >>> import re
    >>> datepat = re.compile(r'(d+)/(d+)/(d+)')
    >>> datepat.sub(r'3-1-2', text)
    'Today is 2012-11-27. PyCon starts 2013-3-13.'
    result, n  = re.subn(r'(d+)/(d+)/(d+)', r'3-1-2', text)

    re.subn()可以知道替换次数

     
  • 相关阅读:
    朱刘算法---有向图的最小生成树
    527D Clique Problem 判断一维线段没有两辆相交的最大线段数量
    Tex中的引号
    DAY 96 flask05
    DAY 95 flask04
    DAY 94 flask03
    DAY 93 flask02
    DAY 92 flask01
    DAY 91 爬虫05
    DAY 90 爬虫04
  • 原文地址:https://www.cnblogs.com/xiyuan2016/p/10334650.html
Copyright © 2020-2023  润新知