¿Cómo encontrar todas las apariciones de una subcadena?
Frecuentes
Visto 551,132 equipos
437
Python tiene string.find()
y string.rfind()
para obtener el índice de una subcadena en una cadena.
Me pregunto si hay algo como string.find_all()
que puede devolver todos los índices encontrados (no solo el primero desde el principio o el primero desde el final).
Por ejemplo:
string = "test test test test"
print string.find('test') # 0
print string.rfind('test') # 15
#this is the goal
print string.find_all('test') # [0,5,10,15]
24 Respuestas
618
No hay una función de cadena incorporada simple que haga lo que está buscando, pero podría usar la más poderosa expresiones regulares:
import re
[m.start() for m in re.finditer('test', 'test test test test')]
#[0, 5, 10, 15]
Si desea encontrar coincidencias superpuestas, mirar hacia el futuro lo haré:
[m.start() for m in re.finditer('(?=tt)', 'ttt')]
#[0, 1]
Si desea buscar todo inverso sin superposiciones, puede combinar una búsqueda anticipada positiva y negativa en una expresión como esta:
search = 'tt'
[m.start() for m in re.finditer('(?=%s)(?!.{1,%d}%s)' % (search, len(search)-1, search), 'ttt')]
#[1]
re.finditer
devuelve un generador, para que puedas cambiar el []
en lo anterior a ()
para obtener un generador en lugar de una lista, lo que será más eficiente si solo está iterando los resultados una vez.
contestado el 16 de mayo de 18 a las 16:05
Desea examinar las expresiones regulares en general: docs.python.org/2/howto/regex.html. La solución a su pregunta será: [m.start () for m in re.finditer ('te [sx] t', 'text test text test')] - Yotam Vaknin
¿Cuál será la complejidad temporal de utilizar este método? - Pranjal Mittal
@PranjalMittal. ¿Límite superior o inferior? ¿Mejor, peor o promedio de los casos? - Físico loco
@marcog ¿y si la subcadena contiene paréntesis u otros caracteres especiales? - plátano
También recomendaría escapar de las cadenas de búsqueda, así: [m.start() for m in re.finditer(re.escape(search_str), input_str)]
- Srctaha
133
>>> help(str.find)
Help on method_descriptor:
find(...)
S.find(sub [,start [,end]]) -> int
Por lo tanto, podemos construirlo nosotros mismos:
def find_all(a_str, sub):
start = 0
while True:
start = a_str.find(sub, start)
if start == -1: return
yield start
start += len(sub) # use start += 1 to find overlapping matches
list(find_all('spam spam spam spam', 'spam')) # [0, 5, 10, 15]
No se requieren cadenas temporales o expresiones regulares.
Respondido 23 Jul 14, 05:07
Para obtener coincidencias superpuestas, debería ser suficiente reemplazar start += len(sub)
a start += 1
. - Carlos Knechtel
Creo que su comentario anterior debería ser una posdata en su respuesta. - tzot
Su código no funciona para encontrar substr: "ATAT" en "GATATATGCATATACTT" - Ashish Negi
Vea el comentario que hice además. Ese es un ejemplo de coincidencia superpuesta. - Carlos Knechtel
Para igualar el comportamiento de re.findall
, Recomiendo agregar len(sub) or 1
en lugar de len(sub)
, de lo contrario, este generador nunca terminará en una subcadena vacía. - GTH
58
Aquí hay una forma (muy ineficiente) de obtener todos (es decir, incluso superpuestos) coincide con:
>>> string = "test test test test"
>>> [i for i in range(len(string)) if string.startswith('test', i)]
[0, 5, 10, 15]
Respondido 21 Abr '13, 09:04
Si queremos verificar muchos caracteres usando 1 for loop, ¿cómo se puede hacer? con este código, tendré muchos bucles for y el orden de tiempo es demasiado alto. - Profesor Plaga
@thkala Una forma muy inteligente de realizar la operación sin el uso del módulo re. ¡Gracias por la respuesta! - Lindo panda
41
Nuevamente, hilo antiguo, pero aquí está mi solución usando un generador y claro str.find
.
def findall(p, s):
'''Yields all the positions of
the pattern p in the string s.'''
i = s.find(p)
while i != -1:
yield i
i = s.find(p, i+1)
Ejemplo
x = 'banananassantana'
[(i, x[i:i+2]) for i in findall('na', x)]
devoluciones
[(2, 'na'), (4, 'na'), (6, 'na'), (14, 'na')]
Respondido el 23 de diciembre de 15 a las 23:12
esto se ve hermoso! - fabio.sang
probado y es dos veces más rápido que el re.finditer
solución: 310 ns ± 5.35 ns per loop
para la solución con str.find
vs 799 ns ± 5.72 ns per loop
para la solución con re.finditer
(en mi máquina). Confirma lo que he notado en el pasado: los métodos de cadena incorporados son generalmente más rápidos que las expresiones regulares (lo mismo para anidado str.replace
vs re.sub
) - Juan Monet
La solución más bonita. Tenga en cuenta que se puede generalizar fácilmente introduciendo un parámetro opcional overlapping=True
y reemplazando i+1
by i + (1 if overlapping else len(p))
. - Hugues
25
Puedes usar re.finditer()
para coincidencias que no se superponen.
>>> import re
>>> aString = 'this is a string where the substring "is" is repeated several times'
>>> print [(a.start(), a.end()) for a in list(re.finditer('is', aString))]
[(2, 4), (5, 7), (38, 40), (42, 44)]
pero no se trabajar para:
In [1]: aString="ababa"
In [2]: print [(a.start(), a.end()) for a in list(re.finditer('aba', aString))]
Output: [(0, 3)]
Respondido 27 Feb 18, 06:02
¿Por qué hacer una lista con un iterador? Simplemente ralentiza el proceso. - pradyunsg
aString VS astring;) - SiguienteD.
20
Ven, volvamos juntos.
def locations_of_substring(string, substring):
"""Return a list of locations of a substring."""
substring_length = len(substring)
def recurse(locations_found, start):
location = string.find(substring, start)
if location != -1:
return recurse(locations_found + [location], location+substring_length)
else:
return locations_found
return recurse([], 0)
print(locations_of_substring('this is a test for finding this and this', 'this'))
# prints [0, 27, 36]
No es necesario utilizar expresiones regulares de esta forma.
respondido 01 nov., 13:03
Empecé a preguntarme "¿hay una forma elegante de localizar una subcadena dentro de una cadena en Python" ... y luego, después de 5 minutos de búsqueda en Google, encontré su código. ¡¡¡Gracias por compartir!!! - Geparada
Este código tiene varios problemas. Dado que está trabajando con datos abiertos, tarde o temprano te encontrarás RecursionError
si hay suficientes ocurrencias. Otra son dos listas desechables que crea en cada iteración solo por agregar un elemento, que es muy subóptimo para una función de búsqueda de cadenas, que posiblemente podría llamarse muchas veces. Aunque a veces las funciones recursivas parecen elegantes y claras, deben tomarse con precaución. - Iván Nikoláyev
12
Si solo está buscando un solo carácter, esto funcionaría:
string = "dooobiedoobiedoobie"
match = 'o'
reduce(lambda count, char: count + 1 if char == match else count, string, 0)
# produces 7
También, trabaja para
string = "test test test test"
match = "test"
len(string.split(match)) - 1
# produces 4
Mi corazonada es que ninguno de estos (especialmente el # 2) tiene un desempeño terrible.
Respondido el 24 de Septiembre de 14 a las 22:09
solución gr8 .. estoy impresionado con el uso de .. split () - Shantanu Pathak
10
Este es un hilo antiguo, pero me interesé y quería compartir mi solución.
def find_all(a_string, sub):
result = []
k = 0
while k < len(a_string):
k = a_string.find(sub, k)
if k == -1:
return result
else:
result.append(k)
k += 1 #change to k += len(sub) to not search overlapping results
return result
Debería devolver una lista de posiciones donde se encontró la subcadena. Por favor comente si ve un error o margen de mejora.
Respondido 01 Abr '15, 10:04
6
Esto me hace el truco usando re.finditer
import re
text = 'This is sample text to test if this pythonic '\
'program can serve as an indexing platform for '\
'finding words in a paragraph. It can give '\
'values as to where the word is located with the '\
'different examples as stated'
# find all occurances of the word 'as' in the above text
find_the_word = re.finditer('as', text)
for match in find_the_word:
print('start {}, end {}, search string \'{}\''.
format(match.start(), match.end(), match.group()))
Respondido 06 Jul 18, 10:07
5
Este hilo es un poco viejo pero esto funcionó para mí:
numberString = "onetwothreefourfivesixseveneightninefiveten"
testString = "five"
marker = 0
while marker < len(numberString):
try:
print(numberString.index("five",marker))
marker = numberString.index("five", marker) + 1
except ValueError:
print("String not found")
marker = len(numberString)
contestado el 17 de mayo de 16 a las 13:05
5
Puedes probar :
>>> string = "test test test test"
>>> for index,value in enumerate(string):
if string[index:index+(len("test"))] == "test":
print index
0
5
10
15
Respondido 27 Feb 18, 06:02
2
Cualesquiera que sean las soluciones proporcionadas por otros, se basan completamente en el método disponible find () o cualquier método disponible.
¿Cuál es el algoritmo básico central para encontrar todas las apariciones de una subcadena en una cadena?
def find_all(string,substring):
"""
Function: Returning all the index of substring in a string
Arguments: String and the search string
Return:Returning a list
"""
length = len(substring)
c=0
indexes = []
while c < len(string):
if string[c:c+length] == substring:
indexes.append(c)
c=c+1
return indexes
También puede heredar la clase str a la nueva clase y puede usar esta función a continuación.
class newstr(str):
def find_all(string,substring):
"""
Function: Returning all the index of substring in a string
Arguments: String and the search string
Return:Returning a list
"""
length = len(substring)
c=0
indexes = []
while c < len(string):
if string[c:c+length] == substring:
indexes.append(c)
c=c+1
return indexes
Llamar al método
newstr.find_all ('¿Te parece útil esta respuesta? ¡Entonces vota esto!', 'esto')
Respondido 15 Feb 18, 20:02
2
Cuando busque una gran cantidad de palabras clave en un documento, utilice flashtexto
from flashtext import KeywordProcessor
words = ['test', 'exam', 'quiz']
txt = 'this is a test'
kwp = KeywordProcessor()
kwp.add_keywords_from_list(words)
result = kwp.extract_keywords(txt, span_info=True)
Flashtext se ejecuta más rápido que las expresiones regulares en una gran lista de palabras de búsqueda.
Respondido el 28 de Septiembre de 18 a las 18:09
2
Esta función no examina todas las posiciones dentro de la cadena, no desperdicia recursos de cálculo. Mi intento:
def findAll(string,word):
all_positions=[]
next_pos=-1
while True:
next_pos=string.find(word,next_pos+1)
if(next_pos<0):
break
all_positions.append(next_pos)
return all_positions
para usarlo llámalo así:
result=findAll('this word is a big word man how many words are there?','word')
Respondido el 13 de enero de 20 a las 12:01
1
src = input() # we will find substring in this string
sub = input() # substring
res = []
pos = src.find(sub)
while pos != -1:
res.append(pos)
pos = src.find(sub, pos + 1)
contestado el 16 de mayo de 20 a las 18:05
Si bien este código puede resolver el problema del OP, es mejor incluir una explicación de cómo su código aborda el problema del OP. De esta manera, los futuros visitantes pueden aprender de su publicación y aplicarla a su propio código. SO no es un servicio de codificación, sino un recurso de conocimiento. Además, es más probable que se voten a favor las respuestas completas y de alta calidad. Estas características, junto con el requisito de que todas las publicaciones sean independientes, son algunas de las fortalezas de SO como plataforma, que la diferencia de los foros. Puede editar para agregar información adicional y / o complementar sus explicaciones con la documentación de origen - sherylhohman
1
Esta es la solución a una pregunta similar de hackerrank. Espero que esto pueda ayudarte.
import re
a = input()
b = input()
if b not in a:
print((-1,-1))
else:
#create two list as
start_indc = [m.start() for m in re.finditer('(?=' + b + ')', a)]
for i in range(len(start_indc)):
print((start_indc[i], start_indc[i]+len(b)-1))
Salida:
aaadaa
aa
(0, 1)
(1, 2)
(4, 5)
Respondido el 03 de junio de 20 a las 17:06
1
def find_index(string, let):
enumerated = [place for place, letter in enumerate(string) if letter == let]
return enumerated
por ejemplo:
find_index("hey doode find d", "d")
devoluciones:
[4, 7, 13, 15]
respondido 08 nov., 20:14
¿Has leído realmente la pregunta? Intentar print(find_index('test test test test', 'test'))
que es el ejemplo que dio la operación. - Timus
0
No es exactamente lo que pidió OP, pero también podría usar el función dividida para obtener una lista de dónde están todas las subcadenas no ocurrir. OP no especificó el objetivo final del código, pero si su objetivo es eliminar las subcadenas de todos modos, esto podría ser una simple frase. Probablemente hay formas más eficientes de hacer esto con cadenas más grandes; las expresiones regulares serían preferibles en ese caso
# Extract all non-substrings
s = "an-example-string"
s_no_dash = s.split('-')
# >>> s_no_dash
# ['an', 'example', 'string']
# Or extract and join them into a sentence
s_no_dash2 = ' '.join(s.split('-'))
# >>> s_no_dash2
# 'an example string'
Hice un breve vistazo de otras respuestas, así que me disculpo si esto ya está ahí.
contestado el 19 de mayo de 21 a las 14:05
0
def count_substring(string, sub_string):
c=0
for i in range(0,len(string)-2):
if string[i:i+len(sub_string)] == sub_string:
c+=1
return c
if __name__ == '__main__':
string = input().strip()
sub_string = input().strip()
count = count_substring(string, sub_string)
print(count)
Respondido el 02 de junio de 21 a las 04:06
0
si solo quieres usar numpy aquí hay una solución
import numpy as np
S= "test test test test"
S2 = 'test'
inds = np.cumsum([len(k)+len(S2) for k in S.split(S2)[:-1]])- len(S2)
print(inds)
Respondido el 10 de junio de 21 a las 17:06
-1
Al dividir encontramos todas las combinaciones posibles y las agregamos en una lista y encontramos el número de veces que ocurre usando count
función
s=input()
n=len(s)
l=[]
f=input()
print(s[0])
for i in range(0,n):
for j in range(1,n+1):
l.append(s[i:j])
if f in l:
print(l.count(f))
Respondido 30 Jul 19, 13:07
Cuándo s="test test test test"
y f="test"
su código se imprime 4
, pero OP esperado [0,5,10,15]
- barbasan
Haber escrito una sola palabra actualizará el código - BONTHA SREEVIDHYA
-2
por favor mire el código a continuación
#!/usr/bin/env python
# coding:utf-8
'''黄哥Python'''
def get_substring_indices(text, s):
result = [i for i in range(len(text)) if text.startswith(s, i)]
return result
if __name__ == '__main__':
text = "How much wood would a wood chuck chuck if a wood chuck could chuck wood?"
s = 'wood'
print get_substring_indices(text, s)
respondido 16 mar '17, 01:03
-2
La forma pitónica sería:
mystring = 'Hello World, this should work!'
find_all = lambda c,s: [x for x in range(c.find(s), len(c)) if c[x] == s]
# s represents the search string
# c represents the character string
find_all(mystring,'o') # will return all positions of 'o'
[4, 7, 20, 26]
>>>
Respondido 10 Abr '18, 21:04
1) ¿Cómo ayuda esto a una pregunta que fue respondida hace 7 años? 2) Usar lambda
de esta manera no es Pythonic y va en contra de PEP8. 3) Esto no proporciona la salida correcta para la situación de los OP - grillo maravilloso
Pythonic no significa "Use tantas funciones de Python como pueda imaginar" - klutt
-3
Puedes usar fácilmente:
string.count('test')!
https://www.programiz.com/python-programming/methods/string/count
¡Aclamaciones!
Respondido el 01 de diciembre de 18 a las 19:12
esta debería ser la respuesta - Maxwell Chandler
El método string count () devuelve el número de apariciones de una subcadena en la cadena dada. No es su ubicación. - Astrid
esto no satisface todos los casos, s = 'banana', sub = 'ana'. Sub ocurre en esta situación dos veces, pero hacer s.sub ('ana') devolvería 1 - joey daniel darko
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas python regex string or haz tu propia pregunta.
que debería
'ttt'.find_all('tt')
¿regreso? - Santiago Alessandridebería devolver '0'. Por supuesto, en el mundo perfecto también tiene que haber
'ttt'.rfind_all('tt')
, que debería devolver '1' - nuklParece un duplicado de esto stackoverflow.com/questions/3873361/… - nu everest