Copia le linee selezionate da un file all'altro
Domanda
Sto cercando di scrivere un programma in Python che cerca le parole specificate dall'utente in un file TXT e copia le linee selezionate contenenti quella parola in un altro file.
Anche l'utente avrà un'opzione per escludere qualsiasi parola.
(ad es. Supponiamo che l'utente cerca la parola "Eccezione" e vuoi escludere la parola "ABC", quindi il codice copierà solo le linee che ha "Eccezione" in esso ma non "ABC"). Ora tutto il lavoro verrà eseguito dal prompt dei comandi.
L'ingresso sarebbe:
file.py test.txt(input file) test_mod.txt(output file) -e abc(exclude word denoted by -e)-s exception(search word denoted by -s)
.
Ora l'utente avrà un'opzione per inserire più parole escluse e più parole di ricerca.
Ora finora ho raggiunto che il formato di input è:
file.py test.txt test_mod.txt abc exception".
.
Esclude la parola "ABC" e cerca "Eccezione".
Ma non so come:
- .
- Includi più parole di ricerca multipla ed escludere parole
- Come indicarli by -e e -s. Ho visto l'ArgParse e il tutorial Getopt. Ma non c'è tutorial su questo argomento specifico.
Per favore qualcuno può aiutarmi a modificare il mio codice o scrivi uno nuovo?
Ecco il mio codice di cui ora:
#/Python33
import sys
import os
def main(): #main method
try:
f1 = open(sys.argv[1], 'r') #takes the first input file in command line
found = False
user_input1 = (sys.argv[3]) #takes the word which is to be excluded.
user_input2 = (sys.argv[4]) #takes the word which is to be included.
if sys.argv[1] == sys.argv[2]:
f1.close()
sys.exit('\nERROR!!\nThe two file names cannot be the same.')
if sys.argv[3] != sys.argv[4]:
for line in f1:
if user_input1 in line or user_input2 in line:
f2 = open(sys.argv[2], 'a')
if user_input1 in line:
if user_input2 in line:
pass
elif user_input2 in line:
f2.write(line)
found = True
f2.close()
if not found:
print("ERROR: The Word couldn't be found.")
f1.close()
if sys.argv[3] == sys.argv[4]:
f1.close()
sys.exit('\nERROR!!\nThe word to be excluded and the word to be included cannot be the same.')
except IOError:
print('\nIO error or wrong file name.')
except IndexError:
print('\nYou must enter 5 parameters.') #prevents less than 5 inputs which is mandatory
except SystemExit as e: #Exception handles sys.exit()
sys.exit(e)
if __name__ == '__main__':
main()
.
Grazie uomo. Questo mi ha davvero aiutato a capire la logica. Ma sono nuovo a Python, quindi sto ancora avendo alcuni problemi. Quando l'ho eseguito, copia il file con le parole specificate da -s ma non escludono le parole specificate da -e. Che cosa sto facendo di sbagliato? Quindi ecco il mio codice ora: # / Python33
#takes a text file, finds a word and writes that line containing that word but not a 2nd word specified by the user. So if both of them are there, that line is not printed
import sys
import os
import argparse
def main(): #main method
try:
parser = argparse.ArgumentParser(description='Copies selected lines from files')
parser.add_argument('input_file')
parser.add_argument('output_file')
parser.add_argument('-e',action="append")
parser.add_argument('-s',action="append")
args = parser.parse_args('test.txt, test_mod.txt, -e , -s exception'.split())
user_input1 = (args.e) #takes the word which is to be excluded.
user_input2 = (args.s) #takes the word which is to be included.
def include_exclude(input_file, output_file, exclusion_list=[], inclusion_list=[]):
with open(output_file, 'w') as fo:
with open(input_file, 'r') as fi:
for line in fi:
inclusion_words_in_line = map(lambda x: x in line, inclusion_list)
exclusion_words_in_line = map(lambda x: x in line, exclusion_list)
if any(inclusion_words_in_line) and not any(exclusion_words_in_line):
fo.write(line)
if user_input1 != user_input2 :
include_exclude('test.txt', 'test_mod.txt', user_input1, user_input2);
print("hello")
if user_input1 == user_input2 :
sys.exit('\nERROR!!\nThe word to be excluded and the word to be included cannot be the same.')
except IOError:
print('\nIO error or wrong file name.')
except IndexError:
print('\nYou must enter 5 parameters.')
except SystemExit as e:
sys.exit(e)
if __name__ == '__main__':
main()
.Soluzione
Penso che questo fa ciò che vuoi:
»»» import argparse
»»» parser = argparse.ArgumentParser(description='foo baaar')
»»» parser.add_argument('input_file')
Out[3]: _StoreAction(option_strings=[], dest='input_file', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
»»» parser.add_argument('output_file')
Out[4]: _StoreAction(option_strings=[], dest='output_file', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
»»» parser.add_argument('-e', action="append")
Out[5]: _AppendAction(option_strings=['-e'], dest='e', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
»»» parser.add_argument('-s', action="append")
Out[6]: _AppendAction(option_strings=['-s'], dest='s', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
»»» parser.parse_args('foo1.txt foo2.txt -e abc -e def -s xyz -s pqr'.split())
Out[7]: Namespace(e=['abc', 'def'], input_file='foo1.txt', output_file='foo2.txt', s=['xyz', 'pqr'])
.
Se chiami parser.parse_args()
, analizzerà gli argomenti passati al tuo script, ma quanto sopra è utile per i test. NOTA Come vengono specificate più ricerche ed escludere parole con più flag -s
e -e
. Passando action="append"
al metodo add_argument
, gli argomenti dopo -s
e -e
vengono aggiunti a un elenco nello spazio dei nomi restituito da parser.parse_args
. Questo dovrebbe indirizzare le tue domande 1.
e 2.
.
Ecco un esempio di come è possibile accedere ai valori in un modo carino:
»»» args = parser.parse_args('foo1.txt foo2.txt -e abc -e def -s xyz -s pqr'.split())
»»» args.e
Out[12]: ['abc', 'def']
.
Ho usato il discarse docs , in particolare Il metodo Add_argument DOC è molto utile.
Modifica: Ecco una funzione che fa la logica di inclusione / esclusione:
def include_exclude(input_file, output_file, inclusion_list, exclusion_list=[]):
with open(output_file, 'w') as fo:
with open(input_file, 'r') as fi:
for line in fi:
inclusion_words_in_line = map(lambda x: x in line, inclusion_list)
exclusion_words_in_line = map(lambda x: x in line, exclusion_list)
if any(inclusion_words_in_line) and not any(exclusion_words_in_line):
fo.write(line)
.
L'istruzione with
garantisce che il file sia correttamente chiuso se qualcosa va storto (vedi doc ). Invece, puoi ovviamente usare lo stesso codice aperto / chiudere già. In effetti, il mio codice non include alcuna gestione degli errori, lo lascerò come esercizio per il lettore. Nel circuito principale for
, loopo su tutte le linee nel file di input. Quindi, guardo tutte le parole in Inclusion_List e controlla se si verificano nel line
. The map
Function è imho un modo elegante per farlo; Ci vogliono (ad esempio) le parole in inclusion_list
e genera un altro elenco per mapping ciascuno degli elementi di inclusion_list
alla funzione lambda x: x in line
. La funzione restituisce solo True
se è input (una parola da inclusion_list
appare nella riga), quindi si finisce con un elenco di elementi true / falsi. BREVE ESEMPIO:
»»» line="foo bar"
»»» words=['foo', 'barz']
»»» map(lambda x: x in line, words)
Out[24]: [True, False]
.
Ora applico il any
funzione per controllare se, bene, Tutti gli articoli nell'elenco inclusion_words_in_line
sono veri e per verificare se nessuno (not any
) degli elementi in Exclusion_Words_in_line sono true. Se questo è il caso, il line
viene aggiunto al file di output. Se si desidera assicurarsi che all
delle parole in inclusion_list
appaiono sulla linea, piuttosto che di qualsiasi (questo non è stato chiaro dalla descrizione del tuo problema), è possibile utilizzare all
funzioni invece.
Nota che è possibile risolvere abbastanza facilmente il sopra con i loop che loop su inclusion_list
e exclusion_list
s, controllando se gli elementi sono lì, non è necessario utilizzare map
e any
.