¿Python tiene un método de subcadena 'contiene'?

Estoy buscando un string.contains or string.indexof método en Python.

Quiero hacer:

if not somestring.contains("blah"):
   continue

preguntado el 08 de agosto de 10 a las 23:08

10 Respuestas

Puede utilizar el in operador:

if "blah" not in somestring: 
    continue

respondido 11 nov., 15:23

Debajo del capó, Python usará __contains__(self, item), __iter__(self) y __getitem__(self, key) en ese orden para determinar si un artículo se encuentra en un contenido dado. Implemente al menos uno de esos métodos para hacer in disponible para su tipo personalizado. - Bolígrafo Ben

Solo asegúrate de que alguna cadena no sea None. De lo contrario, obtienes un TypeError: argument of type 'NoneType' is not iterable - Calabaza grande

FWIW, esta es la forma idiomática de lograr dicho objetivo. - Trenton

Para cadenas, Python in operador utiliza el algoritmo de Rabin-Carp? - chats de sam

@SamChats ver stackoverflow.com/questions/18139660/… para los detalles de implementación (en CPython; afaik, la especificación del lenguaje no exige ningún algoritmo en particular aquí). - Christoph Bürschka

Si es solo una búsqueda de subcadena, puede usar string.find("substring").

Tienes que tener un poco de cuidado con find, index y in sin embargo, ya que son búsquedas de subcadenas. En otras palabras, esto:

s = "This be a string"
if s.find("is") == -1:
    print("No 'is' here!")
else:
    print("Found 'is' in the string.")

Se imprimiría Found 'is' in the string. De manera similar, los if "is" in s: evaluaría a True. Esto puede o no ser lo que desea.

Respondido 18 Feb 20, 15:02

+1 para resaltar las trampas involucradas en las búsquedas de subcadenas. la solución obvia es if ' is ' in s: que volverá False como es (probablemente) esperado. - aaronasterling

@aaronasterling Obviamente puede ser, pero no del todo correcto. ¿Qué pasa si tienes puntuación o está al principio o al final? ¿Qué pasa con las mayúsculas? Mejor sería una búsqueda de expresiones regulares que no distingan entre mayúsculas y minúsculas para \bis\b (límites de palabras). - Chelín

@JamieBull Una vez más, debes considerar si deseas incluir la puntuación como delimitador de una palabra. La división tendría en gran parte el mismo efecto que la solución ingenua de verificar ' is ', en particular, no atrapará This is, a comma' or 'It is.'. - Chelín

@JamieBull: Dudo mucho que cualquier entrada real se divida con s.split(string.punctuation + string.whitespace) se dividiría incluso una vez; split no es como el strip/rstrip/lstrip familia de funciones, solo se divide cuando ve todos los caracteres delimitadores, de forma contigua, en ese orden exacto. Si desea dividir en clases de caracteres, regresa a las expresiones regulares (en ese momento, busca r'\bis\b' sin dividir es la forma más sencilla y rápida de hacerlo). - Guardabosques

'is' not in (w.lower() for w in s.translate(string.maketrans(' ' * len(string.punctuation + string.whitespace), string.punctuation + string.whitespace)).split() - ok, punto tomado. Esto ahora es ridículo ... - jamie toro

¿Python tiene un método de cadena que contiene subcadena?

99% de los casos de uso se cubrirán con la palabra clave, in, que regresa True or False:

'substring' in any_string

Para el caso de uso de obtener el índice, use str.find (que devuelve -1 en caso de error y tiene argumentos posicionales opcionales):

start = 0
stop = len(any_string)
any_string.find('substring', start, stop)

or str.index (como el find pero genera ValueError en caso de falla):

start = 100 
end = 1000
any_string.index('substring', start, end)

Explicación

Use el in operador de comparación porque

  1. el lenguaje pretende su uso, y
  2. otros programadores de Python esperarán que lo use.
>>> 'foo' in '**foo**'
True

El opuesto (complemento), que pedía la pregunta original, es not in:

>>> 'foo' not in '**foo**' # returns False
False

Esto es semánticamente lo mismo que not 'foo' in '**foo**' pero es mucho más legible y se proporciona explícitamente en el lenguaje como una mejora de la legibilidad.

Evitar el uso de __contains__

El método "contiene" implementa el comportamiento para in. Este ejemplo,

str.__contains__('**foo**', 'foo')

devoluciones True. También puede llamar a esta función desde la instancia de la supercuerda:

'**foo**'.__contains__('foo')

Pero no lo hagas. Los métodos que comienzan con guiones bajos se consideran semánticamente no públicos. La única razón para usar esto es al implementar o extender la in y not in funcionalidad (por ejemplo, si se subclasifica str):

class NoisyString(str):
    def __contains__(self, other):
        print(f'testing if "{other}" in "{self}"')
        return super(NoisyString, self).__contains__(other)

ns = NoisyString('a string with a substring inside')

y ahora:

>>> 'substring' in ns
testing if "substring" in "a string with a substring inside"
True

No use find y index para probar "contiene"

No utilice los siguientes métodos de cadena para probar "contiene":

>>> '**foo**'.index('foo')
2
>>> '**foo**'.find('foo')
2

>>> '**oo**'.find('foo')
-1
>>> '**oo**'.index('foo')

Traceback (most recent call last):
  File "<pyshell#40>", line 1, in <module>
    '**oo**'.index('foo')
ValueError: substring not found

Es posible que otros lenguajes no tengan métodos para probar directamente las subcadenas, por lo que tendría que usar este tipo de métodos, pero con Python, es mucho más eficiente usar el in operador de comparación.

Además, estos no son reemplazos directos para in. Puede que tenga que manejar la excepción o -1 casos, y si vuelven 0 (porque encontraron la subcadena al principio) la interpretación booleana es False en lugar de True.

Si realmente quieres decir not any_string.startswith(substring) Entonces dilo.

Comparaciones de desempeño

Podemos comparar varias formas de lograr el mismo objetivo.

import timeit

def in_(s, other):
    return other in s

def contains(s, other):
    return s.__contains__(other)

def find(s, other):
    return s.find(other) != -1

def index(s, other):
    try:
        s.index(other)
    except ValueError:
        return False
    else:
        return True



perf_dict = {
'in:True': min(timeit.repeat(lambda: in_('superstring', 'str'))),
'in:False': min(timeit.repeat(lambda: in_('superstring', 'not'))),
'__contains__:True': min(timeit.repeat(lambda: contains('superstring', 'str'))),
'__contains__:False': min(timeit.repeat(lambda: contains('superstring', 'not'))),
'find:True': min(timeit.repeat(lambda: find('superstring', 'str'))),
'find:False': min(timeit.repeat(lambda: find('superstring', 'not'))),
'index:True': min(timeit.repeat(lambda: index('superstring', 'str'))),
'index:False': min(timeit.repeat(lambda: index('superstring', 'not'))),
}

Y ahora vemos que usando in es mucho más rápido que los demás. Menos tiempo para hacer una operación equivalente es mejor:

>>> perf_dict
{'in:True': 0.16450627865128808,
 'in:False': 0.1609668098178645,
 '__contains__:True': 0.24355481654697542,
 '__contains__:False': 0.24382793854783813,
 'find:True': 0.3067379407923454,
 'find:False': 0.29860888058124146,
 'index:True': 0.29647137792585454,
 'index:False': 0.5502287584545229}

Respondido 21 ago 20, 14:08

¿Por qué debería uno evitar str.index y str.find? ¿De qué otra manera sugeriría que alguien busque el índice de una subcadena en lugar de simplemente si existe o no? (o quiso decir que evite usarlos en lugar de contiene, así que no use s.find(ss) != -1 en lugar de ss in s?) - codificador para la vida

Precisamente así, aunque la intención detrás del uso de esos métodos puede abordarse mejor mediante el uso elegante de la re módulo. Todavía no he encontrado un uso para str.index o str.find en ningún código que haya escrito todavía. - Aaron Hall ♦

Amplíe su respuesta a los consejos contra el uso str.count también (string.count(something) != 0). estremecimiento - cs95

Cómo hace el operator versión del módulo ¿llevar a cabo? - jpmc26

Esta es una excelente respuesta a una necesidad universal en Python. ¡Gracias por brindar algunas explicaciones detalladas! - Rico Lysakowski PhD

if needle in haystack: es el uso normal, como dice @Michael - se basa en el in operador, más legible y más rápido que una llamada a un método.

Si realmente necesita un método en lugar de un operador (por ejemplo, para hacer algo extraño key= para un tipo muy peculiar ...?), eso sería 'haystack'.__contains__. Pero dado que su ejemplo es para usar en una if, Supongo que no te refieres a lo que dices ;-). No es una buena forma (ni legible, ni eficiente) usar métodos especiales directamente; están destinados a ser utilizados, en cambio, a través de los operadores y las funciones integradas que les delegan.

Respondido el 20 de junio de 15 a las 05:06

in Cadenas y listas de Python

A continuación se muestran algunos ejemplos útiles que hablan por sí mismos sobre la in método:

>>> "foo" in "foobar"
True
>>> "foo" in "Foobar"
False
>>> "foo" in "Foobar".lower()
True
>>> "foo".capitalize() in "Foobar"
True
>>> "foo" in ["bar", "foo", "foobar"]
True
>>> "foo" in ["fo", "o", "foobar"]
False
>>> ["foo" in a for a in ["fo", "o", "foobar"]]
[False, False, True]

Consideración. Las listas son iterables y el in El método actúa sobre iterables, no solo cadenas.

Respondido 28 Feb 21, 08:02

¿Se podría cambiar la lista iterable para buscar algo de la lista en una sola cadena? Ex: ["bar", "foo", "foobar"] in "foof"? - Mike con cafeína

@CaffeinatedCoder, no, esto requiere una iteración anidada. Lo mejor es unirse a la lista con tuberías "|" .join (["bar", "foo", "foobar"]) y compilar una expresión regular a partir de ella, luego hacer coincidir "foof" - lince de fuego

cualquiera ([x en "foof" para x en ["bar", "foo", "foobar"]]) - Izaak Weiss

@IzaakWeiss Su única línea funciona, pero no es muy legible y tiene una iteración anidada. Aconsejaría no hacer esto: lince de fuego

@ PiyushS.Wanare, ¿a qué te refieres con complejidad? El "WTF / min" es mucho más alto con expresiones regulares. - lince de fuego

Si estas contento con "blah" in somestring pero quieres que sea una llamada a función / método, probablemente puedas hacer esto

import operator

if not operator.contains(somestring, "blah"):
    continue

Todos los operadores en Python se pueden encontrar más o menos en el módulo operador incluso in.

respondido 09 nov., 19:12

Entonces, aparentemente, no hay nada similar para la comparación vectorial. Una forma obvia de Python de hacerlo sería:

names = ['bob', 'john', 'mike']
any(st in 'bob and john' for st in names) 
>> True

any(st in 'mary and jane' for st in names) 
>> False

Respondido 06 Abr '16, 09:04

Eso es porque hay mil millones de formas de crear un Producto a partir de variables atómicas. Puede colocarlos en una tupla, una lista (que son formas de productos cartesianos y vienen con un orden implícito), o pueden ser propiedades nombradas de una clase (sin orden a priori) o valores de diccionario, o pueden ser archivos en un directorio, o lo que sea. Siempre que pueda identificar de forma única (iter o getitem) algo en un 'contenedor' o 'contexto', puede ver ese 'contenedor' como una especie de vector y definir operaciones binarias en él. es.wikipedia.org/wiki/… - niriel

No vale nada que in no debe usarse con listas porque hace un escaneo lineal de los elementos y es lento en comparación. En su lugar, utilice un conjunto, especialmente si las pruebas de pertenencia se van a realizar repetidamente. - cs95

Puedes usar y.count().

Devolverá el valor entero del número de veces que una subcadena aparece en una cadena.

Por ejemplo:

string.count("bah") >> 0
string.count("Hello") >> 1

Respondido el 26 de Septiembre de 19 a las 08:09

contar una cuerda es costoso cuando solo quieres comprobar si está ahí ... - Jean-François Fabre ♦

métodos que existen en la publicación original de 2010, así que terminé eliminándolos, con el consenso de la comunidad (ver meta publicación meta.stackoverflow.com/questions/385063/…) - Jean-François Fabre ♦

No. Mi punto es "¿por qué responder exactamente lo mismo que otros hicieron hace 9 años"? - Jean-François Fabre ♦

porque estoy moderando el sitio ... hice la pregunta en meta meta.stackoverflow.com/questions/385063/… - Jean-François Fabre ♦

Es casi seguro que cambiar a la derecha no es lo que quiere hacer aquí. - rsandwick3

Esta es tu respuesta:

if "insert_char_or_string_here" in "insert_string_to_search_here":
    #DOSTUFF

Para comprobar si es falso:

if not "insert_char_or_string_here" in "insert_string_to_search_here":
    #DOSTUFF

O:

if "insert_char_or_string_here" not in "insert_string_to_search_here":
    #DOSTUFF

contestado el 03 de mayo de 18 a las 15:05

Es interesante saber que podría hacer si no tan bien como si no estuviera en. Arturo Bowers

Puede usar expresiones regulares para obtener las ocurrencias:

>>> import re
>>> print(re.findall(r'( |t)', to_search_in)) # searches for t or space
['t', ' ', 't', ' ', ' ']

contestado el 17 de mayo de 19 a las 06:05

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.