4
votes

Comment imprimer une partie de la chaîne de 'commence par' jusqu'à 'se termine par'

J'aime enregistrer des parties du fichier texte d'origine, qui peuvent être identifiées entre les chaînes «commence par» et «se termine par», dans un nouveau fichier texte.

Exemple: Le fichier texte d'entrée contient les lignes suivantes: p>

with open('file_in.txt','r') as fi:
    id = []
    for ln in fi:
        if ln.startswith("start with string"):
            if ln.endswith("ends with string"):
                id.append(ln[:])
                with open(file_out.txt, 'a', encoding='utf-8') as fo:
                    fo.write (",".join(id))
print(id)

Je suis intéressé à extraire les lignes suivantes dans le fichier texte de sortie:

starts with string...def...ends with string
starts with string...mno...ends with string

Mon code suivant renvoie une liste vide []. Veuillez aider à corriger mon code.

...abc…
...starts with string...
...def...
...ends with string...
...ghi...

...jkl...
...starts with string...
...mno...
...ends with string...
...pqr...

Je m'attends à ce que le fichier.out.txt contienne, toutes les chaînes commençant par "commencer par la chaîne" et se terminant par "se terminant par chaîne ".


1 commentaires

Merci pour la mise à jour avec les données de test. J'ai mis à jour ma réponse en conséquence, veuillez vérifier si elle correspond à vos besoins.


3 Réponses :


1
votes

commence avec et endswith renvoie Vrai ou Faux plutôt qu'une position que vous pouvez utiliser pour trancher votre chaîne. Essayez find ou index à la place. Par exemple:

start = 'starts with string'
end = 'ends with string'
s = '...abc… ...starts with string... ...def... ...ends with string... ...ghi...'

sub = s[s.find(start):s.find(end) + len(end)]
print(sub)
# starts with string... ...def... ...ends with string

Vous devrez ajouter un peu de vérification dans votre boucle pour voir si les chaînes de début et de fin existent car find renverra -1 s'il y a il n'y a pas de correspondance et cela entraînerait un découpage involontaire.


0 commentaires

1
votes

Vous pouvez utiliser une variable distincte pour indiquer si la ligne courante fait partie d'une section intéressante et basculer cette variable en fonction des marqueurs de début et de fin. Ensuite, vous pouvez également transformer cette fonction en générateur:

import itertools as it

def extract(fh, start, stop):
    while any(start in x for x in fh):
        yield from it.takewhile(lambda x: stop not in x, fh)

with open('test.txt') as fh:
    print(''.join(extract(fh, 'starts with string', 'ends with string')))

En Python 3.8, vous pouvez utiliser expressions d'affectation :

import itertools as it

def extract(fh, start, stop):
    while any(start in (line := x) for x in fh):
        yield line
        yield from it.takewhile(lambda x: stop not in x, ((line := y) for y in fh))
        yield line

with open('test.txt') as fh:
    print(''.join(extract(fh, 'starts with string', 'ends with string')))

Variante: à l'exclusion des marqueurs de début et d'arrêt

En cas de démarrage et d'arrêt les marqueurs doivent être exclus de la sortie, nous pouvons à nouveau utiliser itertools.take While :

def extract(fh, start, stop):
    sub = False
    for line in fh:
        sub |= start in line
        if sub:
            yield line
            sub ^= stop in line

with open('test.txt') as fh:
    print(''.join(extract(fh, 'starts with string', 'ends with string')))


4 commentaires

@MadPhysicist J'ai mis à jour ma réponse pour répondre aux exigences de l'OP (inclure les marqueurs de démarrage et d'arrêt dans la sortie), également avec un exemple d'utilisation.


@a_guest: Utilisation des 'expressions d'affectation': erreur suivante:> Fichier "", ligne 4 pendant tout (commencez dans (ligne: = x) pour x dans fh): ^ SyntaxError: syntaxe invalide


@anatta Comme mentionné, les expressions d'affectation ont été introduites dans Python 3.8 qui n'est actuellement disponible qu'en alpha version .


@a_guest: Je l'ai manqué. Je vais mettre à jour vers la version 3.8 alpha et essayer. Merci.



1
votes

À la fin de chaque ligne, un caractère indique à l'ordinateur d'afficher une nouvelle ligne. Je suppose ici que "commencer par une chaîne" et "se terminer par une chaîne" sont sur la même ligne. Si ce n'est pas le cas, ajoutez - "id.append (ln [:])" - directement sous la première instruction if.

Essayez

with open('C:\\Py\\testing.txt','r') as fi:
    id = []
    x = 0
    copy_line = False
    for ln in fi:
        if "starts with string" in ln:
            copy_line = True
        if copy_line:
            id.append ( ln[:] )
        if "ends with string" in ln :
            copy_line = False

    with open ('C:\\Py\\testing_out.txt', 'a', encoding='utf-8' ) as fo:
        fo.write (",".join(id))

print(id)

ou

ln.endswith("ends with string"+'\n' +'\r')
ln.endswith("ends with string"+'\n' )


2 commentaires

Renvoie toujours une liste vide []. Je vais essayer quelques variantes une mise à jour. Merci.


J'ai une autre stratégie pour utiliser un opérateur booléen. Voir le code mis à jour.