Vérifiez si plusieurs chaînes existent dans une autre chaîne

378

Comment puis-je vérifier si l'une des chaînes d'un tableau existe dans une autre chaîne?

Comme:

a = ['a', 'b', 'c']
str = "a123"
if a in str:
  print "some of the strings found in str"
else:
  print "no strings found in str"

Ce code ne fonctionne pas, c'est juste pour montrer ce que je veux réaliser.

jahmax
la source
5
Je suis surpris qu'il n'y ait pas (encore) de réponses comparées à une expression régulière compilée en termes de perf, en particulier par rapport à la taille de la chaîne et au nombre "d'aiguilles" à rechercher.
Pat
3
@Pat je ne suis pas surpris. La question ne concerne pas les performances. Aujourd'hui, la plupart des programmeurs se soucient davantage de la réalisation et de la lisibilité. La question des performances est valide, mais une question différente.
guettli
13
L'utilisation de str comme variable est source de confusion et peut entraîner un comportement inattendu car il s'agit d'un mot réservé; voir le lien .
Clever Guy
regex [abc]fonctionne également parfaitement bien et sera plus rapide s'il y a plus de deux candidats à tester. Mais si les chaînes sont arbitraires et que vous ne les connaissez pas à l'avance pour construire une expression régulière, vous devrez utiliser l' any(x in str for x in a)approche.
smci
@CleverGuy Vous avez raison, même si ce n'est pas un mot réservé, sinon vous ne pourriez pas lui attribuer. C'est une fonction intégrée.
wjandrea

Réponses:

717

Vous pouvez utiliser any:

a_string = "A string is more than its parts!"
matches = ["more", "wholesome", "milk"]

if any(x in a_string for x in matches):

De même, pour vérifier si toutes les chaînes de la liste sont trouvées, utilisez allplutôt que any.

Mark Byers
la source
11
any () prend un itérable. Je ne sais pas quelle version de Python vous utilisez mais en 2.6 vous devrez mettre [] autour de votre argument à any (). any ([x en str pour x en a]) afin que la compréhension renvoie un itérable. Mais peut-être que les versions ultérieures de Python le font déjà.
emispowder
7
@Mark Byers: Désolé pour le commentaire tardif, mais existe-t-il un moyen d'imprimer la chaîne trouvée? Comment ferais-tu ceci. Je vous remercie.
Shankar Kumar
3
Je ne suis pas sûr de comprendre, si a est la liste et si str est la chose à comparer, quel est le x? Python newbie ftw. :)
rouge
2
@red: vous pouvez lire for x in acomme "pour chaque élément de la liste". Depuis aest une liste de chaînes, et xest un élément de cette liste, xest une chaîne (l'une de 'a', 'b', 'c' dans l'exemple d'origine)
User
6
@emispowder Cela fonctionne bien pour moi tel quel dans Python 2.6.9.
MPlanchard
67

any()est de loin la meilleure approche si tout ce que vous voulez est Trueou False, mais si vous voulez savoir spécifiquement quelle chaîne / chaîne correspond, vous pouvez utiliser quelques éléments.

Si vous voulez la première correspondance (avec Falsepar défaut):

match = next((x for x in a if x in str), False)

Si vous souhaitez obtenir toutes les correspondances (y compris les doublons):

matches = [x for x in a if x in str]

Si vous souhaitez obtenir toutes les correspondances non dupliquées (sans tenir compte de l'ordre):

matches = {x for x in a if x in str}

Si vous souhaitez obtenir toutes les correspondances non dupliquées dans le bon ordre:

matches = []
for x in a:
    if x in str and x not in matches:
        matches.append(x)
zondo
la source
veuillez également ajouter un exemple pour le dernier match
Oleg Kokorin
@OlegKokorin: Il crée une liste de chaînes correspondantes dans le même ordre qu'il les trouve, mais il ne conserve que la première si deux sont identiques.
zondo
Utiliser un OrderedDictest probablement plus performant qu'une liste. Voir cette réponse sur "Supprimer les doublons dans les listes"
wjandrea
44

Vous devez être prudent si les cordes aou strs'allongent. Les solutions simples prennent O (S * (A ^ 2)), où Sest la longueur de stret A est la somme des longueurs de toutes les chaînes a. Pour une solution plus rapide, regardez l' algorithme Aho-Corasick pour la correspondance de chaînes, qui s'exécute en temps linéaire O (S + A).

jbernadas
la source
Aho-Corasick peut-il également trouver des sous-chaînes au lieu de préfixes?
RetroCode
1
Certaines bibliothèques python Aho-Corasick sont ici et ici
vorpal
23

Juste pour ajouter de la diversité avec regex:

import re

if any(re.findall(r'a|b|c', str, re.IGNORECASE)):
    print 'possible matches thanks to regex'
else:
    print 'no matches'

ou si votre liste est trop longue - any(re.findall(r'|'.join(a), str, re.IGNORECASE))

Shankar ARUL - jupyterdata.com
la source
1
Cela fonctionne pour le cas d'utilisation donné de la question. Si vous recherchez (ou que *cela échoue, car la citation de la syntaxe regex doit être effectuée.
guettli
2
Vous pouvez y échapper si nécessaire avec '|'.join(map(re.escape, strings_to_match)). Vous devriez probablement re.compile('|'.join(...))aussi.
Artyer
12

Vous devez répéter les éléments de a.

a = ['a', 'b', 'c']
str = "a123"
found_a_string = False
for item in a:    
    if item in str:
        found_a_string = True

if found_a_string:
    print "found a match"
else:
    print "no match found"
Seamus Campbell
la source
2
Oui, je savais comment le faire, mais par rapport à la réponse de Marks, c'est un code horrible.
jahmax
11
Seulement si vous comprenez le code de Mark. Le problème que vous rencontriez est que vous n'examiniez pas les éléments de votre tableau. Il existe de nombreuses façons concises et pythoniques d'accomplir ce que vous voulez qui cacheraient l'essence de ce qui n'allait pas avec votre code.
Seamus Campbell
10
Il peut s'agir d'un «code horrible», mais c'est exactement ce que fait any () . En outre, cela vous donne la chaîne réelle qui correspond, tandis que any () vous indique simplement qu'il existe une correspondance.
alldayremix
4

jbernadas a déjà mentionné l' algorithme Aho-Corasick afin de réduire la complexité.

Voici une façon de l'utiliser en Python:

  1. Télécharger aho_corasick.py depuis ici

  2. Mettez-le dans le même répertoire que votre fichier Python principal et nommez-le aho_corasick.py

  3. Essayez l'alrorithme avec le code suivant:

    from aho_corasick import aho_corasick #(string, keywords)
    
    print(aho_corasick(string, ["keyword1", "keyword2"]))

Notez que la recherche est sensible à la casse

Domi W
la source
3
a = ['a', 'b', 'c']
str =  "a123"

a_match = [True for match in a if match in str]

if True in a_match:
  print "some of the strings found in str"
else:
  print "no strings found in str"
mluebke
la source
1

Cela dépend du contexte, supposez que si vous voulez vérifier un seul littéral comme (n'importe quel mot simple a, e, w, .. etc.) en est suffisant

original_word ="hackerearcth"
for 'h' in original_word:
      print("YES")

si vous voulez vérifier l'un des caractères parmi le mot d'origine: utilisez

if any(your_required in yourinput for your_required in original_word ):

si vous voulez toutes les entrées que vous voulez dans ce mot d'origine, utilisez tous les simples

original_word = ['h', 'a', 'c', 'k', 'e', 'r', 'e', 'a', 'r', 't', 'h']
yourinput = str(input()).lower()
if all(requested_word in yourinput for requested_word in original_word):
    print("yes")
Trinadh Koya
la source
Quelle serait votre contribution? Je peux reconnaître deux choses: la phrase où je cherche quelque chose. L'éventail de mots que je recherche. Mais vous décrivez trois variables et je ne peux pas obtenir ce qu'est la troisième.
mayid
1

Juste plus d'informations sur la façon d'obtenir tous les éléments de liste disponibles dans String

a = ['a', 'b', 'c']
str = "a123" 
list(filter(lambda x:  x in str, a))
Nilesh Birari
la source
1

Une approche étonnamment rapide consiste à utiliser set:

a = ['a', 'b', 'c']
str = "a123"
if set(a) & set(str):
    print("some of the strings found in str")
else:
    print("no strings found in str")

Cela fonctionne si ane contient pas de valeurs à plusieurs caractères (auquel cas utilisez anycomme indiqué ci - dessus ). Si oui, il est plus simple de spécifier acomme une chaîne: a = 'abc'.

Berislav Lopac
la source
0
flog = open('test.txt', 'r')
flogLines = flog.readlines()
strlist = ['SUCCESS', 'Done','SUCCESSFUL']
res = False
for line in flogLines:
     for fstr in strlist:
         if line.find(fstr) != -1:
            print('found') 
            res = True


if res:
    print('res true')
else: 
    print('res false')

exemple d'image de sortie

LeftSpace
la source
0

J'utiliserais ce genre de fonction pour la vitesse:

def check_string(string, substring_list):
    for substring in substring_list:
        if substring in string:
            return True
    return False
Ivan Mikhailov
la source
0
data = "firstName and favoriteFood"
mandatory_fields = ['firstName', 'lastName', 'age']


# for each
for field in mandatory_fields:
    if field not in data:
        print("Error, missing req field {0}".format(field));

# still fine, multiple if statements
if ('firstName' not in data or 
    'lastName' not in data or
    'age' not in data):
    print("Error, missing a req field");

# not very readable, list comprehension
missing_fields = [x for x in mandatory_fields if x not in data]
if (len(missing_fields)>0):
    print("Error, missing fields {0}".format(", ".join(missing_fields)));
Robert I
la source