Bajo el capó, Python utilizará __contains__(self, item), __iter__(self)y __getitem__(self, key)en ese orden a determinar si un elemento se encuentra en un determinado contiene. Implemente al menos uno de esos métodos para que esté indisponible para su tipo personalizado.
BallpointBen
27
Solo asegúrate de que somestring no sea None. De lo contrario, obtienes unTypeError: argument of type 'NoneType' is not iterable
Big Pumpkin
55
FWIW, esta es la forma idiomática de lograr dicho objetivo.
Trenton
66
Para cadenas, ¿ inutiliza el operador Python el algoritmo Rabin-Carp?
Sam Chats
3
@SamChats, consulte stackoverflow.com/questions/18139660/… para ver los detalles de implementación (en CPython; afaik, la especificación del idioma no exige ningún algoritmo en particular aquí).
Christoph Burschka
667
Si es solo una búsqueda de subcadenas, puede usarla string.find("substring").
Usted tiene que ser un poco cuidadoso con find, indexy insin embargo, a medida que se subcadena búsquedas. 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 de Found 'is' in the string.manera similar, if "is" in s:se evaluaría a True. Esto puede o no ser lo que quieres.
+1 para resaltar las trampas involucradas en las búsquedas de subcadenas. la solución obvia es if ' is ' in s:cuál regresará Falsecomo se espera (probablemente).
aaronasterling
95
@aaronasterling Obvio que puede ser, pero no del todo correcto. ¿Qué pasa si tiene puntuación o está al principio o al final? ¿Qué pasa con la capitalización? Mejor sería una búsqueda de expresiones regulares sin distinción entre mayúsculas y minúsculas \bis\b(límites de palabras).
Bob
2
@JamieBull Una vez más, debe considerar si desea incluir la puntuación como delimitador de una palabra. Dividir tendría en gran medida el mismo efecto que la solución ingenua de verificar ' is ', en particular, no atrapará This is, a comma'o no 'It is.'.
Bob
77
@JamieBull: Dudo mucho que cualquier división de entrada real s.split(string.punctuation + string.whitespace)se dividiría incluso una vez; splitno es como la familia de funciones strip/ rstrip/ lstrip, solo se divide cuando ve todos los caracteres delimitadores, contiguamente, en ese orden exacto. Si desea dividir en clases de caracteres, vuelve a las expresiones regulares (en ese momento, buscar r'\bis\b'sin dividir es la forma más sencilla y rápida de hacerlo).
ShadowRanger
8
'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 Bull
190
¿Python tiene una cadena que contiene el método de subcadena?
Sí, pero Python tiene un operador de comparación que debería usar en su lugar, porque el lenguaje pretende su uso, y otros programadores esperarán que lo use. Esa palabra clave es in, que se utiliza como operador de comparación:
>>>'foo'in'**foo**'True
El opuesto (complemento), que pide la pregunta original, es not in:
>>>'foo'notin'**foo**'# returns FalseFalse
Esto es semánticamente igual, not 'foo' in '**foo**'pero es mucho más legible y se proporciona explícitamente en el lenguaje como una mejora de legibilidad.
Evitar el uso __contains__, findyindex
Según lo prometido, este es el containsmétodo:
str.__contains__('**foo**','foo')
vuelve True. También podría llamar a esta función desde la instancia de la supercadena:
'**foo**'.__contains__('foo')
Pero no lo hagas. Los métodos que comienzan con guiones bajos se consideran semánticamente privados. La única razón para usar esto es cuando se extiende la funcionalidad iny not in(por ejemplo, si se subclasifica str):
classNoisyString(str):def __contains__(self, other):print('testing if "{0}" in "{1}"'.format(other, 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
Además, evite los siguientes métodos de cadena:
>>>'**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
Otros lenguajes pueden no tener 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 inoperador de comparación.
Comparaciones de rendimiento
Podemos comparar varias formas de lograr el mismo objetivo.
¿Por qué se debe evitar str.indexy str.find? ¿De qué otra forma sugeriría que alguien encuentre el índice de una subcadena en lugar de solo si existe o no? (¿o quiso decir evitar usarlos en lugar de s.find(ss) != -1ss in s
contenedores
3
Precisamente, aunque la intención detrás del uso de esos métodos puede abordarse mejor mediante el uso elegante del remódulo. Todavía no he encontrado un uso para str.index o str.find en cualquier código que haya escrito todavía.
Aaron Hall
Extienda su respuesta a los consejos contra el uso str.counttambién ( string.count(something) != 0). estremecimiento
if needle in haystack:es el uso normal, como dice @Michael: se basa en el inoperador, más legible y más rápido que una llamada a método.
Si realmente necesita un método en lugar de un operador (por ejemplo, hacer algo extraño key=para un tipo muy peculiar ...?), Sería 'haystack'.__contains__. Pero dado que su ejemplo es para usar en un if, supongo que realmente no quiere decir lo que dice ;-). 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 incorporaciones que les delegan.
Aquí hay algunos ejemplos útiles que hablan por sí mismos sobre el inmé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 inmétodo actúa en iterables, no solo en cadenas.
¿Se podría cambiar la lista iterable para buscar cualquiera de la lista en una sola cadena? Ej ["bar", "foo", "foobar"] in "foof":?
CaffeinatedCoder
1
@CaffeinatedCoder, no, esto requiere una iteración anidada. Mejor hacerlo uniendo la lista con las tuberías "|" .join (["bar", "foo", "foobar"]) y compilando una expresión regular de él, luego haciendo coincidir con "foof"
firelynx
2
any ([x en "foof" para x en ["bar", "foo", "foobar"]])
Izaak Weiss
1
@IzaakWeiss Tu único forro funciona, pero no es muy fácil de leer, y tiene una iteración anidada.
Aconsejaría no
1
@ PiyushS.Wanare, ¿qué quieres decir con complejidad? El "WTF / min" es mucho más alto con regex.
firelynx
42
Si está satisfecho con "blah" in somestringpero quiere que sea una llamada de función / método, probablemente pueda hacer esto
Esto se debe a que hay miles de millones de formas de crear un Producto a partir de variables atómicas. Puede rellenarlos en una tupla, una lista (que son formas de productos cartesianos y vienen con un orden implícito), o pueden denominarse propiedades 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. en.wikipedia.org/wiki/…
Niriel
No vale nada que inno deba usarse con listas porque hace un escaneo lineal de los elementos y es lento en comparación. Utilice un conjunto en su lugar, especialmente si las pruebas de membresía se deben realizar repetidamente.
cs95
22
Puedes usar y.count().
Devolverá el valor entero de la cantidad de veces que aparece una subcadena en una cadena.
contar una cadena es costoso cuando solo quieres verificar si está allí ...
Jean-François Fabre
3
métodos que existen en la publicación original de 2010, así que terminé editándolos, con el consenso de la comunidad (ver meta publicación meta.stackoverflow.com/questions/385063/… )
Jean-François Fabre
17
No. Mi punto es "¿por qué responder exactamente lo mismo que otros hicieron hace 9 años"?
luego, si tiene la autoridad para eliminarlo, elimínelo, de lo contrario, haga lo que debe y continúe. En mi opinión, esta respuesta agrega valor, lo que se refleja en los votos positivos de los usuarios.
__contains__(self, item)
,__iter__(self)
y__getitem__(self, key)
en ese orden a determinar si un elemento se encuentra en un determinado contiene. Implemente al menos uno de esos métodos para que estéin
disponible para su tipo personalizado.TypeError: argument of type 'NoneType' is not iterable
in
utiliza el operador Python el algoritmo Rabin-Carp?Si es solo una búsqueda de subcadenas, puede usarla
string.find("substring")
.Usted tiene que ser un poco cuidadoso con
find
,index
yin
sin embargo, a medida que se subcadena búsquedas. En otras palabras, esto:Se imprimiría de
Found 'is' in the string.
manera similar,if "is" in s:
se evaluaría aTrue
. Esto puede o no ser lo que quieres.fuente
if ' is ' in s:
cuál regresaráFalse
como se espera (probablemente).\bis\b
(límites de palabras).' is '
, en particular, no atraparáThis is, a comma'
o no'It is.'
.s.split(string.punctuation + string.whitespace)
se dividiría incluso una vez;split
no es como la familia de funcionesstrip
/rstrip
/lstrip
, solo se divide cuando ve todos los caracteres delimitadores, contiguamente, en ese orden exacto. Si desea dividir en clases de caracteres, vuelve a las expresiones regulares (en ese momento, buscarr'\bis\b'
sin dividir es la forma más sencilla y rápida de hacerlo).'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 ...Sí, pero Python tiene un operador de comparación que debería usar en su lugar, porque el lenguaje pretende su uso, y otros programadores esperarán que lo use. Esa palabra clave es
in
, que se utiliza como operador de comparación:El opuesto (complemento), que pide la pregunta original, es
not in
:Esto es semánticamente igual,
not 'foo' in '**foo**'
pero es mucho más legible y se proporciona explícitamente en el lenguaje como una mejora de legibilidad.Evitar el uso
__contains__
,find
yindex
Según lo prometido, este es el
contains
método:vuelve
True
. También podría llamar a esta función desde la instancia de la supercadena:Pero no lo hagas. Los métodos que comienzan con guiones bajos se consideran semánticamente privados. La única razón para usar esto es cuando se extiende la funcionalidad
in
ynot in
(por ejemplo, si se subclasificastr
):y ahora:
Además, evite los siguientes métodos de cadena:
Otros lenguajes pueden no tener 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.Comparaciones de rendimiento
Podemos comparar varias formas de lograr el mismo objetivo.
Y ahora vemos que usar
in
es mucho más rápido que los demás. Menos tiempo para hacer una operación equivalente es mejor:fuente
str.index
ystr.find
? ¿De qué otra forma sugeriría que alguien encuentre el índice de una subcadena en lugar de solo si existe o no? (¿o quiso decir evitar usarlos en lugar des.find(ss) != -1
ss in s
re
módulo. Todavía no he encontrado un uso para str.index o str.find en cualquier código que haya escrito todavía.str.count
también (string.count(something) != 0
). estremecimientooperator
versión del módulo ?in_
anterior, pero con un marco de pila alrededor, por lo que es más lento que eso: github.com/python/cpython/blob/3.7/Lib/operator.py#L153if needle in haystack:
es el uso normal, como dice @Michael: se basa en elin
operador, más legible y más rápido que una llamada a método.Si realmente necesita un método en lugar de un operador (por ejemplo, hacer algo extraño
key=
para un tipo muy peculiar ...?), Sería'haystack'.__contains__
. Pero dado que su ejemplo es para usar en unif
, supongo que realmente no quiere decir lo que dice ;-). 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 incorporaciones que les delegan.fuente
in
Python cadenas y listasAquí hay algunos ejemplos útiles que hablan por sí mismos sobre el
in
método:Consideración. Las listas son iterables, y el
in
método actúa en iterables, no solo en cadenas.fuente
["bar", "foo", "foobar"] in "foof"
:?Si está satisfecho con
"blah" in somestring
pero quiere que sea una llamada de función / método, probablemente pueda hacer estoTodos los operadores en Python se pueden encontrar más o menos en el módulo del operador incluido
in
.fuente
Entonces, aparentemente no hay nada similar para la comparación vectorial. Una forma obvia de hacerlo en Python sería:
fuente
in
no deba usarse con listas porque hace un escaneo lineal de los elementos y es lento en comparación. Utilice un conjunto en su lugar, especialmente si las pruebas de membresía se deben realizar repetidamente.Puedes usar
y.count()
.Devolverá el valor entero de la cantidad de veces que aparece una subcadena en una cadena.
Por ejemplo:
fuente
Aquí está tu respuesta:
Para verificar si es falso:
O:
fuente
Puede usar expresiones regulares para obtener las ocurrencias:
fuente