心存善意,定能途遇天使。
”问
有这样一字符串,'ab;cd|efg|hi,jkl|mn\topq;rst,uvw\txyz',如何根据分隔符 ; , | \t 进行拆分?
答
解决方案:
方案一:连续使用str.split()方法,每次只能处理一种分隔号
■ map()+str.split()
■ sum()+str.split()
■ reduce()+map()+sum()+str.split()
方案二:使用正则表达式的re.split()方法。(推荐!!!)
PS: 处理一个分隔符的时候使用方法一(一个的时候,方法二会比一慢);多个分隔符的时候使用方法二
连续使用str.split()
我们先来小试牛刀。
In [1]: s = 'ab;cd|efg|hi,jkl|mn\topq;rst,uvw\txyz'# 注意: str.split('|,;') 这样写的话 会将 |,; 整体当作成1个分隔符In [2]: s.split('|')Out[2]: ['ab;cd', 'efg', 'hi,jkl', 'mn\topq;rst,uvw\txyz']In [3]: [ss.split(';') for ss in s.split('|')]Out[3]: [['ab', 'cd'], ['efg'], ['hi,jkl'], ['mn\topq', 'rst,uvw\txyz']]
不难看出,当第二次分割的时候,分割结果就变成了二维了。我们需要使用str.split()继续分割,就必须进行降维处理,将二维变成一维。降维处理,可以使用前面学到的
map()函数
,还可以使用sum()函数。
先注意一个列表添加的小细节,append()跟extend()有着很大的不同。
In [13]: t1 = []In [14]: t1.append(['ab', 'cd'])# 添加的是列表In [15]: t1Out[15]: [['ab', 'cd']]In [16]: t2 = []In [17]: t2.extend(['ab', 'cd'])# 添加的是列表里的元素In [18]: t2Out[18]: ['ab', 'cd']
map()函数依次作用于序列的每一个元素,并返回一个生成器,这时候,我们就应该想到使用map()操作二维里面的每一个元素,如何个操作法呢?因为二维里的这些个元素是列表,所以使用extend()添加进新的列表里,就实现了降维。
In [1]: s = 'ab;cd|efg|hi,jkl|mn\topq;rst,uvw\txyz'In [3]: [ss.split(';') for ss in s.split('|')]Out[3]: [['ab', 'cd'], ['efg'], ['hi,jkl'], ['mn\topq', 'rst,uvw\txyz']]In [19]: t = []# 注意 这里map返回的结果是[None,None,None,None] 因为东西都到t列表里去啦.# 还要注意一点 map()映射函数 最终结果是生成器!!!!!!!# 不使用list()、tuple()将其序列化的话 里面是不会依次next()运行的 在这里就意味着t依旧是空列表In [20]: list(map(lambda x: t.extend(x), [ss.split(';') for ss in s.split('|')]))Out[20]: [None, None, None, None]In [21]: tOut[21]: ['ab', 'cd', 'efg', 'hi,jkl', 'mn\topq', 'rst,uvw\txyz']
再来琢磨琢磨sum()函数,使用sum()函数将二维转变为一维 "这种方式会有些浪费"。sum(iterable,start=0,/) 设置初始值为空列表。
其执行过程就是空列表与可迭代序列里的每一个元素相加,而列表的加法相当于extend()操作,最终的结果就是由[ ]扩充的列表。
In [22]: sum([ss.split(';') for ss in s.split('|')], [])Out[22]: ['ab', 'cd', 'efg', 'hi,jkl', 'mn\topq', 'rst,uvw\txyz']In [71]: []+['ab', 'cd']+['efg']Out[71]: ['ab', 'cd', 'efg']
综上,总的思想是,先分割一种,再分割另一种,二维降一维后,接着进行分割。我们将这个思想封装成一个接口。
In [51]: def my_split(s, seps): ...: res = [s] ...: for sep in seps: ...: t = [] ...: list(map(lambda ss: t.extend(ss.split(sep)), res)) ...: res = t ...: ...: return res ...: ...:In [52]: my_split(s, ',;|\t')Out[52]: ['ab', 'cd', 'efg', 'hi', 'jkl', 'mn', 'opq', 'rst', 'uvw', 'xyz']
这里注意个细节,res = [s],首先将字符串放进了一个列表里,是为了后面map()映射函数,作用的是列表里的整个字符串,而不是字符串里的每一个字符。这里的处理也很笼统,没有判断当前列表是否是二维,每一步都进行了降维。
------------~您没看错~这是分割线~------------
晕了吗?不慌,还有种看起来更麻烦的玩法。在此之前先来复习下reduce函数。
reduce函数对参数迭代器中的元素进行类累积
格式为:reduce(func,iter,init)
func为函数,iter为序列,init为固定初始值,无初始值时从序列的第一个参数开始
from functools import reduce# 使用reduce函数 举例:计算列表和def add(x, y) : # 两数相加 return x + yreduce(add, [1,2,3,4,5]) # 计算列表和:1+2+3+4+5reduce(lambda x, y: x+y, [1,2,3,4,5]) # 使用 lambda 匿名函数reduce(lambda x,y:x+y,['b','c','d','e'],'a') # 'abcde'# 过程: x='a',y='b' -> 执行函数体x+y 即'a'+'b'='ab' /# 将结果给x -> x='ab',y='c' -> 执行函数体....以此类推....
reduce()+map()+sum()+str.split() 正片开始。说实话,看到这代码,真的掉头发。
In [57]: sOut[57]: 'ab;cd|efg|hi,jkl|mn\topq;rst,uvw\txyz'In [58]: from functools import reduceIn [59]: reduce(lambda data, sep: sum(map(lambda ss: ss.split(sep), data), []), ',;|\t', [s])Out[59]: ['ab', 'cd', 'efg', 'hi', 'jkl', 'mn', 'opq', 'rst', 'uvw', 'xyz']
我们尝试着理解下,毕竟reduce、map、sum三兄弟在一起不容易啊。分解步骤,reduce()有初始值[s],即data=[s],sep=',' ,执行函数体里的内容.
In [72]: sOut[72]: 'ab;cd|efg|hi,jkl|mn\topq;rst,uvw\txyz'In [73]: data = [s]In [74]: sep = ','In [75]: sum(map(lambda ss: ss.split(sep), data), [])Out[75]: ['ab;cd|efg|hi', 'jkl|mn\topq;rst', 'uvw\txyz']
将运行结果重新给data,sep=';',再次执行函数体的内容。
In [76]: data = ['ab;cd|efg|hi', 'jkl|mn\topq;rst', 'uvw\txyz']In [77]: sep = ';'In [78]: sum(map(lambda ss: ss.split(sep), data), [])Out[78]: ['ab', 'cd|efg|hi', 'jkl|mn\topq', 'rst', 'uvw\txyz']
以此类推。你会发现,它将前面的知识点全部串联了起来。amazing!
当然,我们可以将其封装成一个接口。
mysplit2 = lambda s, seps:\ reduce(lambda data, sep: sum(map(lambda ss: ss.split(sep), data), []), seps, [s])print(mysplit2(s,',;|\t'))
re.split()
使用re模块里的split(),您会觉得 so easy~
import res = 'ab;cd|efg|hi,jkl|mn\topq;rst,uvw\txyz'# + 代表一个或者多个res = re.split('[;,|\t]+', s)print(res)# ['ab', 'cd', 'efg', 'hi', 'jkl', 'mn', 'opq', 'rst', 'uvw', 'xyz']
END