@
Pipecraft 正则的表现让我有点失望,本以为正则比循环快,实测不是
不过你写的这个正则很精彩,我留下了,其他地方有用,先谢
@
blueboyggh下面两个是我之前写的,效率还可以
下面两个 if minlen>l: return [] 及相关可以省略,因为我的应用场景有词语,不少是“没必要比较”的,所以直接返回空。如果基本是长句,这个判断反而没必要
==================
def matchSubstrings(s:str, ss:str, minlen:int=2, reverse:bool=False):
'''
按出现先后顺序,寻找 s 中,与 ss 任意子串相同的子串\n
叠加的部分只选首个匹配,例如 638 vs 63/38 -> 只返回 63\n
minlen: int 最短匹配长度\n
reverse: bool->True 反向,寻找目标为 ss ,参考为 s
'''
if reverse: s, ss = ss, s
ac = itertools.accumulate
l = len(s)
if minlen>l: return []
lll, pos = 0, 0
for i in range(l - minlen + 1):
sss = [x for x in ac(s[i:])]
sss.reverse()
ll = len(sss)
for j,x in enumerate(sss[:ll - minlen + 1]):
if j>ll-lll and i<pos+lll: break
if x in ss:
lll = len(x)
pos = i
yield x
break
==================
缩进自行处理,基本是遇到冒号结尾的,后面的都向右缩进,没有向左回退的,大概能看懂
1. 说明中的“叠加”情况是比较麻烦的,如果需求不同,写法就不同了
2. 这个主要考虑“顺序”,是全匹配;匹配长度优先是另一种写法,需要 itertools.accumulate(s[::-1])类似,但思路有点区别,参照#6 ;长度优先可以适时 break 只返回“最长匹配”
下面这个是基于 numpy 和 pandas 的,因为是向量函数列操作,所以是全匹配,如果只需要“最长”的话,在某个 yield 后打 break ,或者要在返回结果中再筛选
===================
def rollingByNumpy(s:pd.Series, window):
v = np.lib.stride_tricks.as_strided(s, (len(s) - (window - 1), window), (s.values.strides * 2))
return pd.Series(v.tolist(), index=s.index[window - 1:])
def matchSubstrings4(s:str, ss:str, minlen:int=2, reverse:bool=False, whole:bool=True):
'''
按最大匹配长度的顺序,寻找 s 中,与 ss 任意子串相同的子串\n
叠加的部分默认只选首个匹配,例如 638 vs 63/38 -> 只返回 63 ; whole=False 时则全部返回,返回 63 和 38\n
minlen: int 最短匹配长度\n
reverse: bool->True 反向,寻找目标为 ss ,参考为 s\n
如果之前已经载入 pandas ,此函数略微快些,否则 载入 pandas 耗时较多
'''
if reverse: s, ss = ss, s
s1 = ''.join([x for x in ss if x in s])
l = len(s1)
if minlen>l: return []
s2 = pd.Series(list(s))
if whole:
for w in range(l, minlen-1, -1):
ser = rollingByNumpy(s2, w).str.join('')
ii = ser.index.min()
for i,x in ser.items():
if i<=ii+w: continue
if x in ss:
ii = i
yield x
else:
for w in range(l, minlen-1, -1):
ser = rollingByNumpy(s2, w).str.join('')
for x in ser:
if x in ss: yield x
==================
缩进自行处理,遇到冒号结尾的,后面的都向右缩进,基本没有向左回退的,大概能看懂
else 那行和 if whole 对应,没有缩进,其他都是向右缩进,回复没缩进会混乱
1. rollingByNumpy 因为用途很广,我好多地方用到,不仅是字符串,所以独立一个函数分开
pandas.rolling 不能用在整数、浮点以外的类型,所以需要用 numpy 模拟
rollingByNumpy 不是原创,是参考 so 的答案改的
2. 我原来的函数是重组一个 dataframe 返回的(也不需要 ss 参数),因为后续根据需求不同(不一定是求子串),可以整个 dataframe 统一用一个函数(这里才使用到 ss)同时处理,没必要逐个处理;这里只是按 op 需求跑了一遍循环 yield 结果