【Python练习cookbook】字符串实用操作、正则表达式操作

字符串官方文档:内置类型 — Python 3.7.13 文档

正则表达式官方:re --- 正则表达式操作 — Python 3.10.8 文档

菜鸟教程-正则表达式(排版清晰):Python3 正则表达式 | 菜鸟教程

____________________________________________________________________________________________________

字符串

str.endswith(suffix[, start[, end]])

如果字符串以指定的 suffix 结束返回 True,否则返回 False。 suffix 也可以为由多个供查找的后缀构成的元组。 如果有可选项 start,将从所指定位置开始检查。 如果有可选项 end,将在所指定位置停止比较。

str.startswith(prefix[, start[, end]])

如果字符串以指定的 prefix 开始则返回 True,否则返回 False。 prefix 也可以为由多个供查找的前缀构成的元组。 如果有可选项 start,将从所指定位置开始检查。 如果有可选项 end,将在所指定位置停止比较。

name.startswith(('http:', 'https:', 'ftp:'))
name.endwith(('.txt', '.sh'))

str.replace(oldnew[, count])

返回字符串的副本,其中出现的所有子字符串 old 都将被替换为 new。 如果给出了可选参数 count,则只替换前 count 次出现。

str.rstrip([chars])

返回原字符串的副本,移除其中的末尾字符。 chars 参数为指定要移除字符的字符串。 如果省略或为 None,则 chars 参数默认移除空格符。 实际上 chars 参数并非指定单个后缀;而是会移除参数值的所有组合:

str.lstrip([chars])

移除头部

str.strip([chars])

移除头尾

>>> # Whitespace stripping
>>> s = ' hello world \n'
>>> s.strip()
'hello world'
>>> s.lstrip()
'hello world \n'
>>> s.rstrip()
' hello world'

>>> # Character stripping
>>> t = '-----hello====='
>>> t.lstrip('-')
'hello====='
>>> t.strip('-=')
'hello'

____________________________________________________________________________________________________

正则表达式

re.split(patternstringmaxsplit=0flags=0)

用 pattern 分开 string 。 如果在 pattern 中捕获到括号,那么所有的组里的文字也会包含在列表里,如果(?:)开头则不包含在列表里,但这样不如不用()。如果 maxsplit 非零, 最多进行 maxsplit 次分隔, 剩下的字符全部返回到列表的最后一个元素。

['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.')#\b表示单词边界
['', 'Words', ', ', 'words', ', ', 'words', '.']
>>> re.split(r'\W*', '...words...')#\W匹配非数字字母下划线
['', '', 'w', 'o', 'r', 'd', 's', '', '']
>>> re.split(r'(\W*)', '...words...')
['', '...', '', '', 'w', '', 'o', '', 'r', '', 'd', '', 's', '...', '', '', '']

应用:(分别取出分割符和字符串)

line = 'asdf fjdk; afed, fjek,asdf, foo'
>>> fields = re.split(r'(;|,|\s)\s*', line)
>>> fields
['asdf', ' ', 'fjdk', ';', 'afed', ',', 'fjek', ',', 'asdf', ',', 'foo']
>>> values = fields[::2]
>>> delimiters = fields[1::2] + ['']
>>> values
['asdf', 'fjdk', 'afed', 'fjek', 'asdf', 'foo']
>>> delimiters
[' ', ';', ',', ',', ',', '']
>>> # Reform the line using the same delimiters
>>> ''.join(v+d for v,d in zip(values, delimiters))
'asdf fjdk;afed,fjek,asdf,foo'

re.search(patternstringflags=0)

扫描整个 字符串 找到匹配样式的第一个位置,并返回一个相应的 匹配对象。如果没有匹配,就返回一个 None ; 注意这和找到一个零长度匹配是不同的。

re.match(patternstringflags=0)

如果 string 开始的0或者多个字符匹配到了正则表达式样式,就返回一个相应的 匹配对象 。 如果没有匹配,就返回 None ;注意它跟零长度匹配是不同的。

要想全匹配,注意在pattern最后加上$.

注意即便是 MULTILINE 多行模式, re.match() 也只匹配字符串的开始位置,而不匹配每行开始。

如果你想定位 string 的任何位置,使用 search() 来替代(也可参考 search() vs. match() )

re.findall(patternstringflags=0)

对 string 返回一个不重复的 pattern 的匹配列表, string 从左到右进行扫描,匹配按找到的顺序返回。如果样式里存在一到多个组,就返回一个组合列表;就是一个元组的列表(如果样式里有超过一个组合的话)。空匹配也会包含在结果里。

re.finditer(patternstringflags=0)

pattern 在 string 里所有的非重复匹配,返回为一个迭代器 iterator 保存了 匹配对象 。 string 从左到右扫描,匹配按顺序排列。空匹配也包含在结果里。

应用1:

通常用括号来标注出希望获得的组,并用group获取处理.

.group() or .group(0) 给出整个匹配结果。
 

>>> datepat = re.compile(r'(\d+)/(\d+)/(\d+)')
>>> m = datepat.match('11/27/2012')

>>> # 获取各组内容p
>>> 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()

>>> #找到所有匹配(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
#注意不打括号标出组的区别
datepat = re.compile(r'\d+/\d+/\d+')
datepat.findall(text)
>>>  ['11/27/2012', '3/13/2013']


>>> for m in datepat.finditer(text):
... print(m.groups())
...
('11', '27', '2012')
('3', '13', '2013')

应用2(非贪婪匹配): 

*,+后面跟?实现非贪婪匹配

>>> str_pat = re.compile(r'\"(.*)\"')
>>> text1 = 'Computer says "no."'
>>> str_pat.findall(text1)
['no.']
>>> text2 = 'Computer says "no." Phone says "yes."'
>>> str_pat.findall(text2)
['no." Phone says "yes.']

>>> str_pat = re.compile(r'\"(.*?)\"')
>>> str_pat.findall(text2)
['no.', 'yes.']

(?P<groupname>PATTERN)给group命名
 

>>> TEXT ='the jackalopes are the team of Odessa,TX while the knights are native of Corvallis OR and the mud hens come from Toledo.OH; the whitecaps have their base in Grand Rapids,MI'
>>> PATTERN = re.compile(r'(?P<city>[A-Z][\w\s]+?).(?P<state>TX|OR|OH|MN)')
>>> match = PATTERN.search(TEXT)
>>> match.groupdict() {'city': 'Odessa', 'state': 'TX'}
>>> match.group('city') 'Odessa'
>>> match.group('state') 'TX'
>>> match.group(1), match.group(2) ('Odessa', 'TX')

re.sub(patternreplstringcount=0flags=0)

返回通过使用 repl 替换在 string 最左边非重叠出现的 pattern 而获得的字符串。 如果样式没有找到,则不加改变地返回 string。 repl 可以是字符串或函数;如为字符串,则其中任何反斜杠转义序列都会被处理。 也就是说,\n 会被转换为一个换行符,\r 会被转换为一个回车附,依此类推。 未知的 ASCII 字符转义序列保留在未来使用,会被当作错误来处理。 其他未知转义序列例如 \& 会保持原样。 向后引用像是 \6 会用样式中第 6 组所匹配到的子字符串来替换。 例如:

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

#或写成
>>> datepat = re.compile(r'(\d+)/(\d+)/(\d+)')
>>> datepat.sub(r'\3-\1-\2', text)
'Today is 2012-11-27. PyCon starts 2013-3-13.'

如果 repl 是一个函数,那它会对每个非重复的 pattern 的情况调用。这个函数只能有一个 匹配对象 参数,并返回一个替换后的字符串。比如

>>> from calendar import month_abbr
>>> def change_date(m):
... mon_name = month_abbr[int(m.group(1))]
... return '{} {} {}'.format(m.group(2), mon_name, m.group(3))
...
>>> datepat.sub(change_date, text)
'Today is 27 Nov 2012. PyCon starts 13 Mar 2013.'

样式可以是一个字符串或者一个 样式对象 。

可选参数 count 是要替换的最大次数;count 必须是非负整数。如果忽略这个参数,或者设置为0,所有的匹配都会被替换。空匹配只在不相临连续的情况被更替,所以 sub('x*', '-', 'abxd') 返回 '-a-b--d-' 。

在字符串类型的 repl 参数里,如上所述的转义和向后引用中,\g<name> 会使用命名组合 name,(在 (?P<name>…) 语法中定义) \g<number> 会使用数字组;\g<2> 就是 \2,但它避免了二义性,如 \g<2>0。 \20 就会被解释为组20,而不是组2后面跟随一个字符 '0'。向后引用 \g<0> 把 pattern 作为一整个组进行引用。

re.subn(patternreplstringcount=0flags=0)

行为与 sub() 相同,但是返回一个元组 (字符串, 替换次数).

>>> newtext, n = datepat.subn(r'\3-\1-\2', text)
>>> newtext
'Today is 2012-11-27. PyCon starts 2013-3-13.'
>>> n
2

应用1(大小写忽略匹配):

>>> text = 'UPPER PYTHON, lower python, Mixed Python'
>>> re.findall('python', text, flags=re.IGNORECASE)
['PYTHON', 'python', 'Python']
>>> re.sub('python', 'snake', text, flags=re.IGNORECASE)
'UPPER snake, lower snake, Mixed snake'

#这函数的实现有点特别,因为该函数返回的是replace函数。所以参数处实际是调用的replace
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)
'UPPER SNAKE, lower snake, Mixed Snake'

 byte字符串处理(byteArray也一样)

  byte字符串几乎可用所有字符串相关的方法,只要注意在前面加上b'即可,如:

>>> data = b'Hello World'
>>> data[0:5]
b'Hello'
>>> data.startswith(b'Hello')
True
>>> data.split()
[b'Hello', b'World']
>>> data.replace(b'Hello', b'Hello Cruel')


>>> data = b'FOO:BAR,SPAM'
>>> re.split(b'[:,]',data) # Notice: pattern as bytes
[b'FOO', b'BAR', b'SPAM']


#bytearray
>>> data = bytearray(b'Hello World')
>>> data[0:5]
bytearray(b'Hello')
>>> data.startswith(b'Hello')
True
>>> data.split()
[bytearray(b'Hello'), bytearray(b'World')]
>>> data.replace(b'Hello', b'Hello Cruel')
bytearray(b'Hello Cruel World')

和字符串不同之处:

1.index取值得到整数

>>> a = 'Hello World' # Text string
>>> a[0]
'H'
>>> a[1]
'e'
>>> b = b'Hello World' # Byte string
>>> b[0]
72
>>> b[1]
101

2.format不支持,需要先decode成string,处理好后再encode

>>> b'%10s %10d %10.2f' % (b'ACME', 100, 490.1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for %: 'bytes' and 'tuple'
>>> b'{} {} {}'.format(b'ACME', 100, 490.1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'bytes' object has no attribute 'format'

>>> '{:10s} {:10d} {:10.2f}'.format('ACME', 100, 490.1).encode('ascii')
b'ACME 100 490.10'

笔记:

format函数详细用法:Python format 格式化函数 | 菜鸟教程

format 官方:string — Common string operations — Python 3.10.8 documentation

format详例:PyFormat: Using % and .format() for great good!

笔记:

如下保证都在python可处理范围内:

ascii_text = [word.encode('ascii', errors='replace').decode('ascii') for word in line]

encode和decode相关

https://eli.thegreenplace.net/2012/01/30/the-bytesstr-dichotomy-inpython-3
http://www.diveintopython3.net/strings.html
 

笔记:

(?aiLmsux)

'a''i''L''m''s''u''x' 中的一个或多个) 这个组合匹配一个空字符串;这些字符对正则表达式设置以下标记 re.A (只匹配ASCII字符), re.I (忽略大小写), re.L (语言依赖), re.M (多行模式), re.S (点dot匹配全部字符), re.U (Unicode匹配), and re.X (冗长模式)。 (这些标记在 模块内容 中描述) 如果你想将这些标记包含在正则表达式中,这个方法就很有用,免去了在 re.compile() 中传递 flag 参数。标记应该在表达式字符串首位表示。

(?aiLmsux)re 的语法相当于re.compile(re,flag=re.A|re.I|re.L|re.M|re.S|re.U|re.X)

如:

re.match(r'(?i)python','sdfasldfjasdoifh')
等价于
re.match(r'python','sdfasldfjasdoifh',flags=re.I)

 各语言正则表达式对比:

中文:正则表达式引擎/风味对比

英文:Regular Expressions Reference: Special and Non-Printable Characters 

linux中通配符模式(glob,或 wildcard模式,仅支持*和?的扩展)和regex模式的区别:regex - asterisk(*) and dot-asterisk(.*) in unix regular expression - Stack Overflow

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值