una separar por palabra letras funcion eliminar contar comparar caracteres caracter cadenas cadena python string variable-length prefixes

python - separar - Encontrar si una cadena comienza con uno de los prefijos de longitud variable de una lista



separar palabra en letras python (11)

str.startswith (prefijo [, inicio [, final]]) ¶

Devuelva True si la cadena comienza con el prefijo, de lo contrario, devuelva False. prefijo también puede ser una tupla de prefijos para buscar. Con inicio opcional, pruebe la cadena que comienza en esa posición. Con el extremo opcional, deja de comparar la cuerda en esa posición.

$ ipython Python 3.5.2 (default, Nov 23 2017, 16:37:01) Type ''copyright'', ''credits'' or ''license'' for more information IPython 6.4.0 -- An enhanced Interactive Python. Type ''?'' for help. In [1]: prefixes = ("i_", "c_", "m_", "l_", "d_", "t_", "e_", "b_") In [2]: ''test''.startswith(prefixes) Out[2]: False In [3]: ''i_''.startswith(prefixes) Out[3]: True In [4]: ''d_a''.startswith(prefixes) Out[4]: True

Necesito averiguar si un nombre comienza con alguno de los prefijos de una lista y luego eliminarlo, como:

if name[:2] in ["i_", "c_", "m_", "l_", "d_", "t_", "e_", "b_"]: name = name[2:]

Lo anterior solo funciona para los prefijos de lista con una longitud de dos. Necesito la misma funcionalidad para los prefijos de longitud variable .

¿Cómo se hace de manera eficiente (poco código y buen desempeño)?

Un bucle for itera sobre cada prefijo y luego name.startswith(prefix) para finalmente name.startswith(prefix) el nombre de acuerdo con la longitud del prefijo, pero es una gran cantidad de código, probablemente ineficiente, y "no pitón".

¿Alguien tiene una buena solución?


¿Qué hay de usar el filter ?

prefs = ["i_", "c_", "m_", "l_", "d_", "t_", "e_", "b_"] name = list(filter(lambda item: not any(item.startswith(prefix) for prefix in prefs), name))

Tenga en cuenta que la comparación de cada elemento de la lista con los prefijos se detiene de manera eficiente en la primera coincidencia. Este comportamiento está garantizado por any función que devuelve tan pronto como encuentra un valor True , por ejemplo:

def gen(): print("yielding False") yield False print("yielding True") yield True print("yielding False again") yield False >>> any(gen()) # last two lines of gen() are not performed yielding False yielding True True

O, usando re.match lugar de startswith :

import re patt = ''|''.join(["i_", "c_", "m_", "l_", "d_", "t_", "e_", "b_"]) name = list(filter(lambda item: not re.match(patt, item), name))


Cuando se trata de búsqueda y eficiencia, siempre piense en técnicas de indexación para mejorar sus algoritmos. Si tiene una larga lista de prefijos, puede utilizar un índice en memoria simplemente indexando los prefijos por el primer carácter en un dict .

Esta solución solo vale la pena si tiene una larga lista de prefijos y el rendimiento se convierte en un problema.

pref = ["i_", "c_", "m_", "l_", "d_", "t_", "e_", "b_"] #indexing prefixes in a dict. Do this only once. d = dict() for x in pref: if not x[0] in d: d[x[0]] = list() d[x[0]].append(x) name = "c_abcdf" #lookup in d to only check elements with the same first character. result = filter(lambda x: name.startswith(x),/ [] if name[0] not in d else d[name[0]]) print result


Esto edita la lista sobre la marcha, eliminando los prefijos. La break omite el resto de los prefijos una vez que se encuentra uno para un elemento en particular.

items = [''this'', ''that'', ''i_blah'', ''joe_cool'', ''what_this''] prefixes = [''i_'', ''c_'', ''a_'', ''joe_'', ''mark_''] for i,item in enumerate(items): for p in prefixes: if item.startswith(p): items[i] = item[len(p):] break print items

Salida

[''this'', ''that'', ''blah'', ''cool'', ''what_this'']


Podría usar un regex simple.

import re prefixes = ("i_", "c_", "longer_") re.sub(r''^(%s)'' % ''|''.join(prefixes), '''', name)

O si algo que precede a un guión bajo es un prefijo válido:

name.split(''_'', 1)[-1]

Esto elimina cualquier número de caracteres antes del primer guión bajo.


Regex, probado:

import re def make_multi_prefix_matcher(prefixes): regex_text = "|".join(re.escape(p) for p in prefixes) print repr(regex_text) return re.compile(regex_text).match pfxs = "x ya foobar foo a|b z.".split() names = "xenon yadda yeti food foob foobarre foo a|b a b z.yx zebra".split() matcher = make_multi_prefix_matcher(pfxs) for name in names: m = matcher(name) if not m: print repr(name), "no match" continue n = m.end() print repr(name), n, repr(name[n:])

Salida:

''x|ya|foobar|foo|a//|b|z//.'' ''xenon'' 1 ''enon'' ''yadda'' 2 ''dda'' ''yeti'' no match ''food'' 3 ''d'' ''foob'' 3 ''b'' ''foobarre'' 6 ''re'' ''foo'' 3 '''' ''a|b'' 3 '''' ''a'' no match ''b'' no match ''z.yx'' 2 ''yx'' ''zebra'' no match


Regexes probablemente te dará la mejor velocidad:

prefixes = ["i_", "c_", "m_", "l_", "d_", "t_", "e_", "b_", "also_longer_"] re_prefixes = "|".join(re.escape(p) for p in prefixes) m = re.match(re_prefixes, my_string) if m: my_string = my_string[m.end()-m.start():]


Si define el prefijo como los caracteres antes de un guión bajo, entonces puede verificar

if name.partition("_")[0] in ["i", "c", "m", "l", "d", "t", "e", "b", "foo"] and name.partition("_")[1] == "_": name = name.partition("_")[2]


Un poco difícil de leer, pero esto funciona:

name=name[len(filter(name.startswith,prefixes+[''''])[0]):]


for prefix in prefixes: if name.startswith(prefix): name=name[len(prefix):] break


import re def make_multi_prefix_replacer(prefixes): if isinstance(prefixes,str): prefixes = prefixes.split() prefixes.sort(key = len, reverse=True) pat = r''/b(%s)'' % "|".join(map(re.escape, prefixes)) print ''regex patern :'',repr(pat),''/n'' def suber(x, reg = re.compile(pat)): return reg.sub('''',x) return suber pfxs = "x ya foobar yaku foo a|b z." replacer = make_multi_prefix_replacer(pfxs) names = "xenon yadda yeti yakute food foob foobarre foo a|b a b z.yx zebra".split() for name in names: print repr(name),''/n'',repr(replacer(name)),''/n'' ss = ''the yakute xenon is a|bcdf in the barfoobaratu foobarii'' print ''/n'',repr(ss),''/n'',repr(replacer(ss)),''/n''