字符串和文本

 

 

一、对任意多的分隔符拆分字符串

  字符串对象的split()方法只能处理非常简单的情况,而且不支持多个分隔符,对分隔符周围可能存在的空格也无能为力。

  应该使用 re.split(),需要小心正则表达式模式中的捕获组(capture group)是否包含在了括号中。

  如果用到了捕获组,那么匹配的文本也会包含在最终结果中。

>>> line = 'asdf fkdk; afed, fdsf,asdf,   foo'
>>> re.split(r'[;,\s]\s*',line)
['asdf', 'fkdk', 'afed', 'fdsf', 'asdf', 'foo']

>>> re.split(r'(;|,|\s)\s*',line)
['asdf', ' ', 'fkdk', ';', 'afed', ',', 'fdsf', ',', 'asdf', ',', 'foo']

  如果不想再结果中看到分割字符,但仍想用括号来对正则表达式模式进行分组确保用的是非捕获组,以(?: )的形式指定。

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

 

二、在字符串的开头或结尾处做文本匹配

  使用str.startswith()和str.endswith()方法。

  如果需要同时对多个选项做检查,只需给startswith()和endswitch()提供包含可能选项的元组 即可!

  >>> [name for name in filenames if name.endswith(('.c','.h')) ]

  使用re正则表达式作为替代方案:

  >>> re.match(r'http:|https:|ftp:|', url)

  检查目录有无出现特定文件:

  >>> if any(name.endswith(('.c','.h')) for name in listdir(dirname)):

 

三、利用Shell通配符做字符串匹配

  fnmatch模块提供两个函数,fnmatch()和fnmatchcase(),可用来执行这样的匹配。使用起来更加简单:

>>> from fnmatch import fnmatch,fnmatchcase
>>> fnmatch('foo.txt','*.txt')
>>> fnmatch('foo.txt','?oo.txt')
True
>>> fnmatch('Dat45.csv','Dat[0-9]*')
True
>>> fnmatchcase('foo.txt','*.TXT')
False

  fnmatch()的匹配模式所采用的大小写区分规则和底层文件系统相同(根据操作系统的不同而有所不同)。

  使用fnmatchcase()。完全根据提供的大小写方式来匹配

 

四、文本模式的匹配和查找

  如果要匹配的是简单文字,只需要使用基本的字符串方法就可以了,如:str.find()、str.endswith()、str.startswith()或类似的函数。

  复杂匹配使用正则表达式以及re模块。

  re.match()方法总是尝试在字符串的开头找到匹配项。

  如果想针对整个文本搜索出所有的匹配项,那么就应该使用findall()方法。

  当定义正则表达式时,用括号抱起来的方式引入捕获组,能简化对匹配文本的处理。

  每个组的内容都可以单独提取出来。

  finditer()方法,以迭代的方式找出匹配项。

 

五、查找和替换

  简单文本使用:str.replace()即可。复杂模式使用re.sub()函数。

  例子:将9/10/2019格式改为2019-9-10。

>>> text = 'Today i 9/10/2019  Pycon start 3/13/2013'
>>> import re
>>> re.sub(r'(\d+)/(\d+)/(\d+)',r'\3-\1-\2-',text)
'Today i 2019-9-10-  Pycon start 2013-3-13-'

  对于更加复杂的文本,可以指定一个替换回调函数

datepat = re.compile(r'(\d+)/(\d+)/(\d+)')
from calendar import month_abbr
def change_date(m):
    mon_name = month_abbr[int(m.group(0))]
    return '{} {} {}'.format(m.group(2), mon_name, m.group(1))
datepat.sub(change_date, text)

  替换回调函数的输入参数是一个匹配对象,由match()或find()返回。

  用.group()方法来提取匹配中特定的部分。这个函数应该返回替换后的文本。

  除了得到替换后文本外,还想知道一共完成了多少次替换,可以使用re.subn()。

 

六、不区分大小写的方式对文本做查找和替换

  使用re模块加上re.IGNORECASE标记。

  使用支撑函数,修正待替换文本和匹配文本大小写不吻合情况。

def matchcase(word):
    def replace(m):
        text = m.group()
        if text.isupper():
            return word.upper()
        elif text.islower():
            return word.lower()
        elif text[0].isupper():
            return word.capitalize()
        else:
            return word
    return replace

re.sub('python',matchcase('snake'),text,flags=re.IGNORECASE)

 

七、实现最短匹配的正则表达式

  *操作符在正则表达式中采用贪心策略,所以匹配过程是基于找出最长的可能匹配来进行的。

  只要在*操作符后面加上 ?修饰符就可以了。

>>> text1 = 'Computer says "no." phone says "yes."'
>>> re.findall(r'\"(.*)\"',text1)
['no." phone says "yes.']
>>> re.findall(r'\"(.*?)\"',text1)
['no.', 'yes.']

 

八、多行模式的正则表达式

  .句点并不能匹配换行符。需要添加对换行符的支持

>>> comment = re.compile(r'/\*(.*?)\*/')
>>> comment = re.compile(r'/\*((?:.|\n)*?)\*/')

  (?:.|\n),指定了一个非捕获组(即,这个组只做匹配但不捕获结果,也不会分配组号)

  也可以直接使用re.DOTALL模式,句点符号将匹配所有的字符。  

 

九、将unicode文本统一表示为规范形式

  >>> t1 = unicodedata.normalize('NFC', s1)

  >>> t2 = unicodedata.normalize('NFD', s1)

 

十、正则表达式处理Unicode字符

  能在多个不同的阿拉伯代码页中匹配所有的字符:

  >>> arabic = re.compile('[\u0600-\u06ff\u0750-\u077f\u08a0-\u08ff]+ ')

 

十一、从字符串中去掉不需要的字符

  在字符串的开始、结尾、中间去掉不需要的字符。

  strip()可用来从字符串的开始、结尾处去掉字符;lstrip()和rstrip()可分别从左或者右侧开始执行去掉字符的操作。

  默认情况下这些方法去除的是空格符,但也可以指定其他字符。

with open(filename) as f:
    lines = (line.strip() for line in f)
    for line in lines:
        ...

 

十二、文本过滤和清理

  (1)建立一个转换表,然后使用translate()方法;

remap = {
    ord('\t') : ' ',
    ord('\f') : ' ',
    ord('\r') : None,
}

a = s.translate(remap)

  (2)对文本能做初步的清理,然后结合encode()和decode()操作来修改或清理文本;

t1 = unicodedata.normalize('NFD', s1)
t1.encode('ascii', 'ignore').decode('ascii')

 

十三、对齐文本字符串

  (1)使用字符串的ljust()、rjust()、center()方法。所有这些方法都可以接受一个可选的填充字符。

>>> text.ljust(20,'=')
'Hello World========='

  (2)format(),函数也可以用来完成对齐的任务,合理使用< > ^以及一个期望的宽度值。

  >>> format(text, '>20')

  >>> format(text, '*^20s')

  >>> '{:>10s} {:>10s}'.format('Hello', 'World')

  format好处在于并不特定于字符串,还可以对数字做格式化处理:

  >>> format(1.2345, '>10')

  >>> format(1.2345, '^10.2f')

 

十四、字符串连接及合并

  合并使用join()、+操作符或者直接排列一起,中间不加操作符;

  复杂场景用format。

  +操作符做链接非常低效,在于内存拷贝和垃圾收集产生的影响。每个+=操作符都会创建一个新的字符串对象。

  利用生成器技巧:

  >>> data = ['ACME', 50, 902]

  >>> ','.join(str(d) for d in data)

  打印时连接操作:

  >>> print(a + ':' + b + ':' + c)

  >>> print(':'.join([a, b, c]))

  >>> print(a, b, c, sep=':')

  同I/O操作混合使用:

def combine(source, maxsize):
    parts = []
    size = 0
    for part in source:
        parts.append(part)
        size += len(part) 
        if size < maxsize:
            yield ''.join(parts)
            parts = []
            size = 0
    yield ''.join(parts)

for part in combine(sample(), 32876):
    f.write(part)

 

十五、字符串中的变量名做插值处理

  创建一个字符串,其中嵌入的变量名称会以变量的字符串值形式替换掉。Python并不会直接支持在字符串中对变量做简单的值替换

  (1)使用format()方法。

  >>> s = '{name} has {n} message'

  >>> s.format(name='David', n=33)

  (2)format_map()和vars联合使用。vars还可以用于实例上。

  >>> s.format_map(vars())

  >>> s.format_map(vars( Info('David',37) ))  

  (3)format和format_map缺点,无法处理缺省值。单独定义__missing__()方法的字典类

class safesub(dict):
    def __missing__(self):
        return '{' + key +'}'

s.format_map(safesub(vars()))
'David has {n} message'

 

十六、以固定列数重新格式化文本

  使用textwrap 模块

  >>> print(textwrap.fill(s, 40))

  os.get_terminal_size().columns 来获取终端尺寸大小。

 

十七、在文本中处理HTML和XML实体

  将&entity或&#code这样的HTML或XML实体替换为它们相对应的文本。

  或者我们需要生成文本,但是要对特定的字符做转义处理。

  >>> s =  'as dafsd  "<tag>Hello world</tag>"  asd'

  (1)生成文本,使用html.escape(s, quote=False)

  # as dafsd  "&lt;tag&gt;Hello world&lt;/tag&gt;"  asd'

  (2)替换实体 HTML:

  >>> from html.parser import HTMLParser

  >>> p = HTMLParser()

  >>> p.unescape(s)

  (3)替换实体 XML:

  >>> from xml.sax.saxutils import unescape

  >>> unescape(t)

  

二十、在字节串上执行文本操作

  在字节串(Byte String)上执行常见的文本操作,拆分、搜索和替换。

  特别的需要在正则模式上做处理需要指定字节串的形式。

  >>> re.split(b'[:,]', data)

  print输出区别:

>>> a = 'Hello World'
>>> a[0]
'H'
>>> a[1]
'e'
>>> b = b'Hello World'
>>> b[0]
72
>>> b[1]
101

  字节串上没有格式化操作。

 

posted @ 2019-09-10 08:51  5_FireFly  阅读(344)  评论(0编辑  收藏  举报
web
counter