python 之 字符串处理
分割字符串
根据某个分割符分割
>>> a = '1,2,3,4'
>>> a.split(',')
['', '', '', '']
根据多个分隔符分割
>>> line = 'asdf fjdk; afed, fjek,asdf, foo'
>>> import re
>>> re.split(r'[;,\s]\s*', line)# 用 re 匹配分隔符,
['asdf', 'fjdk', 'afed', 'fjek', 'asdf', 'foo']
如果你在结果列表中保留这些分隔符,可以捕获分组:
>>> fields = re.split(r'(;|,|\s)\s*', line)
>>> fields
['asdf', ' ', 'fjdk', ';', 'afed', ',', 'fjek', ',', 'asdf', ',', 'foo']
如果不保留这些分隔符,但想用分组正则表达式,可以使用非捕获分组:
>>> re.split(r'(?:,|;|\s)\s*', line)
['asdf', 'fjdk', 'afed', 'fjek', 'asdf', 'foo']
匹配字符串开始或结束
检查字符串是否以 某字符开始或结束 可用 startswith() 和 endswith():
>>> filename = 'spam.txt'
>>> filename.endswith('.txt')
True
>>> filename.startswith('file:')
False
>>> url = 'http://www.python.org'
>>> url.startswith('http:')
True
如果你的检查有多种匹配的可能,可以传入一个包含匹配项的元组:
>>> import os
>>> filenames = os.listdir('.')
>>> 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'
>>> any(name.endswith('.py') for name in filenames)
True
其他方式可以用切片 或 re 匹配:
>>> url = 'http://www.python.org'
>>> url[:5] == 'http:' or url[:6] == 'https:' or url[:4] == 'ftp:'
True
>>> import re
>>> url = 'http://www.python.org'
>>> re.match('http:|https:|ftp:', url)
<_sre.SRE_Match object at 0x101253098>
使用shell通配符匹配字符串:
| * | 匹配任意多个字符,包括 0 个 |
| ? | 匹配任意一个字符,必须有一个字符 |
| [char] | 匹配括号中的任意一个字符 |
| [!char] | 匹配任意一个不属于括号中的字符的字符 |
| [:alnum:] | 匹配任意一个字母或者数字 |
| [:alpha:] | 匹配任意一个字母 |
| [:digit:] | 匹配任意一个数字 |
| [:lower:] | 匹配任意一个小写字母 |
| [:upper:] | 匹配任意一个大写字母 |
>>> 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() 来替代。它完全使用你的模式进行匹配。比如:
>>> fnmatchcase('foo.txt', '*.TXT')
False
>>> fnmatchcase('foo.txt', '*.txt')
True
这个函数在处理非文件名字符串中也非常有用:
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']
总结:fnmatch 的能力介于字符串方法和正则表达式之间,如果数据处理中只需要简单的通配符就能完成,fnmatch 或 fnmatchcase 会是个不错的选择。如果需要做文件名的匹配,最好使用 glob 模块。
字符串匹配和搜索
如果只是简单的字符串匹配,字符串方法足够使用了,例如:str.find() , str.startswith() , str.endswith() 。
对于复杂的匹配需要使用正则表达式和re模块:
>>> 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
>>>
re.match() 总是从字符串开始去匹配,如果匹配到,返回 Match 对象。如果没有匹配到,返回 None。
如果想重复使用同一个正则,可以将模式字符串编译为模式对象:
>>> 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
如果不想从字符串开始位置匹配,可以使用 re.search() 或者 re.findall(),re.search() 在第一个匹配到的位置返回一个 Match 对象,如果没有匹配到,则返回 None 。
re.findall() 将匹配到的所有字符串装进列表中返回。
在使用正则时,若表达式中包含分组,re.findall() 返回一个包含 groups 的列表,groups 是一个包含匹配到的所有分组的元组。
>>> 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)
''
>>> m.group(2)
''
>>> m.group(3)
''
>>> m.groups()
('', '', '')
>>> 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)
[('', '', ''), ('', '', '')]
>>> for month, day, year in datepat.findall(text):
... print('{}-{}-{}'.format(year, month, day))
...
2012-11-27
2013-3-13
findall() 会以列表的形式返回结果,如果你想用迭代的形式返回,可以使用 finditer() :
>>> for m in datepat.finditer(text):
... print(m.groups())
...
('', '', '')
('', '', '')
字符串的搜索和替换
对于简单的查找替换,可以使用 str.replace():
>>> text = 'yeah, but no, but yeah, but no, but yeah'
>>> text.replace('yeah', 'yep')
'yep, but no, but yep, but no, but yep'
对于复杂的查找替换,可以使用 re.sub():
>>> 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.'
其中 \3 等指向匹配模式中的分组
对于更加复杂的替换,可以传递一个回调函数:
>>> 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.'
出了替换后的结果以外,如果你还想知道替换了多少个,可以使用 re.subn() 来代替:
>>> newtext, n = datepat.subn(r'\3-\1-\2', text)
>>> newtext
'Today is 2012-11-27. PyCon starts 2013-3-13.'
>>> n
2
如果想在匹配的时候,忽略大小写,可以给 re 提供一个标志参数,re.IGNORECASE:
>>> 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'
这个例子有一个小缺陷,替换字符串不会和匹配字符串的大小写保持一致,可以做如下修改:
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'
re 匹配的结果可能并不准确,例:
>>> 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.']
我们想要的结果是 [ 'no.', 'yes.' ],但很显然,结果不正确。这是因为 * 操作符是贪婪的,会尽可能多的匹配内容。如果想要精准的匹配到 "" 中的内容,可以这样:
>>> str_pat = re.compile(r'\"(.*?)\"')
>>> str_pat.findall(text2)
['no.', 'yes.']
在 .* 后面加上 ? 的作用是改变 re 的匹配模式为 非贪婪模式,就是尽可能少的匹配内容。
re 实现多行匹配模式
. 去匹配任意字符的时候,无法匹配 换行符(\n),例:
>>> comment = re.compile(r'/\*(.*?)\*/')
>>> text1 = '/* this is a comment */'
>>> text2 = '''/* this is a
... multiline comment */
... '''
>>>
>>> comment.findall(text1)
[' this is a comment ']
>>> comment.findall(text2)
[]
对此,你可以修改模式字符串,以增加对换行符的匹配支持:
>>> comment = re.compile(r'/\*((?:.|\n)*?)\*/')
>>> comment.findall(text2)
[' this is a\n multiline comment ']
‘ ?: ’ 的作用是指定这个分组是非捕获分组(也就是它定义了一个仅仅用来做匹配,而不能通过单独捕获或者编号的组)
除此之外,也可以使用标记参数,使 . 能匹配到换行符:
>>> comment = re.compile(r'/\*(.*?)\*/', re.DOTALL)
>>> comment.findall(text2)
[' this is a\n multiline comment ']
简单情况下,re.DATALL 能很好的工作,但如果匹配模式很复杂,它很可能出现问题。所以,最好还是定义自己的正则表达式模式。这里只是提供一种额外的选择。
删除字符串中不需要的字符
可以使用 str.strip()、str.lstrip()、str.rstrip():
>>> # 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'
这些操作不会去除字符串中间的字符,如果想这么做,可以使用 str.replace() 代替。
将 Unicode 文本标准化
在 unicode 中,某些字符可以有多种合法表示:
>>> s1 = 'Spicy Jalape\u00f1o'
>>> s2 = 'Spicy Jalapen\u0303o'
>>> s1
'Spicy Jalapeño'
>>> s2
'Spicy Jalapeño'
>>> s1 == s2
False
>>> len(s1)
14
>>> len(s2)
15
文本 ‘Spicy Jalapeño’ 使用了两种形式表示,一种是整体字符 ‘ñ’(U+00F1)。一种是组合字符, n 后面跟一个 ‘~’ (U+3030)。
在比较字符串时,如果出现这种情况就麻烦了。解决办法是使用 unicodedata 模块将文本标准化:
>>> import unicodedata
>>> t1 = unicodedata.normalize('NFC', s1)
>>> t2 = unicodedata.normalize('NFC', s2)
>>> t1 == t2
True
>>> print(ascii(t1))
'Spicy Jalape\xf1o'
>>> t3 = unicodedata.normalize('NFD', s1)
>>> t4 = unicodedata.normalize('NFD', s2)
>>> t3 == t4
True
>>> print(ascii(t3))
'Spicy Jalapen\u0303o'
其中 ‘NFC’ 和 ‘NFD’ 是字符串标准化的方式。‘NFC’表示字符应该是整体组成,‘NFD’表示字符应该被分解为多个组合字符。
python 同样支持扩展的标准化形式 NFKC 和 NFKD ,它们在处理某些字符串时增加了一些额外的特性:
>>> s = '\ufb01' # A single character
>>> s
' '
>>> unicodedata.normalize('NFD', s)
' '
# Notice how the combined letters are broken apart here
>>> unicodedata.normalize('NFKD', s)
'fi'
>>> unicodedata.normalize('NFKC', s)
'fi'
python 之 字符串处理的更多相关文章
- Python格式化字符串~转
Python格式化字符串 在编写程序的过程中,经常需要进行格式化输出,每次用每次查.干脆就在这里整理一下,以便索引. 格式化操作符(%) "%"是Python风格的字符串格式化操作 ...
- python学习--字符串
python的字符串类型为str 定义字符串可以用 ‘abc' , "abc", '''abc''' 查看str的帮助 在python提示符里 help(str) python基于 ...
- Python格式化字符串和转义字符
地址:http://blog.chinaunix.net/uid-20794157-id-3038417.html Python格式化字符串的替代符以及含义 符 号 说 明 ...
- [转载] python 计算字符串长度
本文转载自: http://www.sharejs.com/codes/python/4843 python 计算字符串长度,一个中文算两个字符,先转换成utf8,然后通过计算utf8的长度和len函 ...
- Python基础-字符串格式化_百分号方式_format方式
Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-3101] This ...
- python判断字符串
python判断字符串 s为字符串s.isalnum() 所有字符都是数字或者字母s.isalpha() 所有字符都是字母s.isdigit() 所有字符都是数字s.islower() 所有字符都是小 ...
- Python格式化字符串
在编写程序的过程中,经常需要进行格式化输出,每次用每次查.干脆就在这里整理一下,以便索引. 格式化操作符(%) "%"是Python风格的字符串格式化操作符,非常类似C语言里的pr ...
- python(七)字符串格式化、生成器与迭代器
字符串格式化 Python的字符串格式化有两种方式:百分号方式.format方式 1.百分号的方式 %[(name)][flags][width].[precision]typecode (name) ...
- Python 的字符串格式化和颜色控制
(部分内容源自武神博客和网络收集.) Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两 ...
- python反转字符串(简单方法)及简单的文件操作示例
Python反转字符串的最简单方法是用切片: >>> a=' >>> print a[::-1] 654321 切片介绍:切片操作符中的第一个数(冒号之前)表示切片 ...
随机推荐
- Java oop创建自定义异常
package com.test; /** *不管是在方法定义时就使用try catch,还是在定义方法时将异常抛出在调用方法时使用try catch都能达到效果 * */public class M ...
- 使用ajax怎么请求跨域资源
1.ajax中添加“xhrFields”和“crossDomain”,如: $.ajax({ url: url, data: data, type: "post", xhrFiel ...
- SpringCloudBus
不重启微服务的情况下更新配置 配置服务端 tensquare_config配置依赖 <dependency> <groupId>org.springframework.clou ...
- HDU 6064 RXD and numbers
传送门 有向图生成树计数 (度数 ->入度->外向树) BEST定理 (不定起点的欧拉回路个数=某点为根的外向树个数(存在欧拉回路->每个点为根的外向树个数相等)*(每个点的度数(存 ...
- 利用bu命令下延迟断点
bu可以针对符号下断点.这里是用bu下延迟断点的意义在于即使目标驱动没有被加载,windbg也允许我们针对符号设置断点.当新加载驱动程序后,windbg就会检查驱动程序中是否包含了设置了延迟断点的函数 ...
- ZOJ-1107-FatMouse and Cheese-dfs+记忆化搜索
FatMouse has stored some cheese in a city. The city can be considered as a square grid of dimension ...
- Python3升级3.6强力Django+杀手级xadmin打造在线教育平台✍✍✍
Python3升级3.6强力Django+杀手级xadmin打造在线教育平台 教程 Xadmin安装方法: settings.py 的配置: users App 下的 adminx.py 的配置:
- [课后作业] 第002讲:用Python设计第一个游戏 | 课后测试题
试题: 0. 什么是BIF? 1. 用课堂上小甲鱼教的方法数一数 Python3 提供了多少个 BIF? 2. 在 Python 看来:'FishC' 和 'fishc' 一样吗? 3. 在小甲鱼看来 ...
- Django框架基础-MTV模型
一个小问题: 什么是根目录:就是没有路径,只有域名..url(r'^$') 补充一张关于wsgiref模块的图片 一.MTV模型 Django的MTV分别代表: Model(模型):和数据库相关的,负 ...
- shell脚本练习05
######################################################################### # File Name: -.sh # Author ...