2012-08-03 16 views
5

To, co chcę zrobić, wydaje się względnie proste, ale dla mojego życia po prostu nie mogę tego zrozumieć. Mam plik .txt jakLista ciągów do liczb całkowitych przy zachowaniu formatu w pytonie

4 2 
6 5 1 
9 4 5 

I chcę nim informacje mają być dostępne do mnie jak tak (to znaczy nie muszę pisać nowy plik .txt, chyba że byłoby to konieczne.) ...

lub, 1 jest odejmowany od każdej liczby, ale formatowanie pozostaje takie samo. Nigdy nie będzie liczby większej niż 1 w oryginale, więc negatywy nie będą możliwe. Cały ten ból głowy wynika z konwersji indeksowania na początek 0 zamiast 1. Co może komplikować to, że oryginalne druki plików jak

['4 2 /n','6 5 1 /n', '9 4 5 /n'] 

co zrobiłem

Dobrze Jego miszmasz z different rzeczy mam found na StackOverflow, ale myślę, że jadę o tym w najbardziej niewygodny sposób. I this jeden nie ma sensu, kiedy wprowadziły go .. chociaż może być na tym samym torze z emisją ze spacjami ..

origianl = open(file, 'r') 
for line in original.readlines(): 
    newline = line.replace(" \n","") 
    finalWithStrings.append(newline) 

finalWithIntegers = [map(int,x) for x in finalWithStrings] 
finalWithIntegers[:] = [x-1 for x in finalWithIntegers] 

mój proces myślowy był, muszę usunąć „/ n” i konwertować te ciągi na liczby całkowite, dzięki czemu mogę od nich odjąć 1. I jakoś zachowaj formatowanie. Ważne jest, aby formatowanie było takie samo, ponieważ każda linia zawiera informacje o podobnie indeksowanej linii innego pliku. Nie chcę widzieć "/ n" w wyniku końcowym (lub instrukcji print), ale nadal chcę mieć wpływ na początek nowej linii. Powyższy kod jednak nie działa z dwóch powodów (które znam).

int(n[:]) zgłasza błąd, ponieważ nie odpowiada spacji i kiedy umieszczam tam wartość (np. 0), kod wypisuje pierwszy numer na każdej z linii i odejmuje jeden .. i umieszcza to wszystko w jednej linii.

[3, 5, 8] 

Tak, wydaje się zbędny wykupienia powrotu karetki i rzucić w inny, ale trzeba zachować formatowanie, a także mają sposób, aby wszystkie numery!

To także nie działa:

for line in original.readlines(): 
    newline = line.replace(" \n","") 
    finalWithStrings.append(newline) 

finalWithIntegers = [map(int,x) for x in finalWithStrings] 
finalWithIntegers[:] = [x-1 for x in finalWithIntegers]  

ale zamiast tylko złym wyjściem to był błąd:

ValueError:invalid literal for int() with base 10:'' 

Czy ktoś ma jakieś pomysły na to, co robię źle tutaj i jak to naprawić? Pracuję z Pythonem 2.6 i jestem początkującym.

Odpowiedz

9
with open("original_filename") as original: 
    for line in original: 
     #if you just want the line as integers: 
     integers = [ int(i) - 1 for i in line.split() ] 
     #do something with integers here ... 

     #if you want to write a new file, use the code below: 
     #new_line = " ".join([ str(int(i) - 1) for i in line.split() ]) 
     #newfile.write(new_line + '\n') 

Otworzyłem twój plik w menedżerze kontekstu w powyższym przykładzie, ponieważ jest to dobra praktyka (od wersji 2.5). Menedżer kontekstu upewnia się, że plik jest poprawnie zamknięty po wyjściu z tego kontekstu.

EDIT

Wygląda na to może być stara się stworzyć listę 2D ...Aby to zrobić, coś jak to będzie działać:

data = [] 
with open("original_filename") as original: 
    for line in original: 
     integers = [ int(i) - 1 for i in line.split() ] 
     data.append(integers) 

Lub, jeśli wolisz 1-liner (ja nie):

with open("original_filename") as original: 
    data = [ [int(i) for i in line.split()] for line in original ] 

Teraz, jeśli go wydrukować:

for lst in data: 
    print (lst) # [3, 1] 
        # [5, 4, 0] 
        # [8, 3, 4] 
+0

Idealne, właśnie tego szukałem! Dziękuję za edytowanie ... było to bardziej specyficzne dla tego, czego potrzebowałem. – Ason

+0

@Ason - Nie ma problemu. Ponownie przeczytałem twoją pocztę nieco ostrożniej i natknąłem się na linię, która mówiła, że ​​nie potrzebujesz jej w nowym pliku, chyba że był to najprostszy sposób, aby to osiągnąć. Tak, zaktualizowałem. – mgilson

+0

+1 Doceniam czas potrzebny na odpowiedź! – Ason

4

Oto dość prosty sposób na osiągnięcie tego za pomocą wyrażeń regularnych. Tu korzyścią jest to, że formatowanie jest gwarantowana pozostać taka sama, ponieważ będzie wymienić numery w miejscu nie dotykając żadnej z białymi znakami:

import re 

def sub_one_repl(match): 
    return str(int(match.group(0))-1) 

for line in original.readlines(): 
    newline = re.sub(r'\d+', sub_one_repl, line).rstrip('\n') 
+0

Dziękuję bardzo za odpowiedź! Nie jestem zaznajomiony z wyrażeniami regularnymi, więc muszę wybrać inną odpowiedź, ponieważ łatwiej ją zrozumieć i zaimplementować, ale +1 za pomoc przyszłym odwiedzającym! – Ason

+0

Świetny pomysł, choć myślę, że masz na myśli 'match.group', a nie' m.group'. Poza tym możesz chcieć, aby 'sub_one_repl' był trochę bezpieczniejszy (tzn. Jeśli wyrażenie nie pasuje do .group spowoduje wyjątek) lub po prostu wykonaj lambdę. Można to również zrobić jako kompilator listy lub wyrażenie generatora: '(re.sub (r '\ d +', lambda m: str (int (m.group (0)) - 1), linia) dla wiersza w oryginale .readlines()) ' –

+1

@AdamParkin - Dzięki, pierwotnie miałem' m' jako argument i zapomniałem zaktualizować funkcję. 'sub_one_repl' będzie wywoływane tylko w przypadku udanych dopasowań, które zawsze będą wszystkimi cyframi, więc powinno być bezpiecznie tak jak jest.Jedna linia jest opcją, ale nadal przenosiłbym 'lambda' poza nią, więc nie odtwarzasz funkcji w każdej iteracji. –

0

Spróbuj:

with open(filepath) as f: 
    for line in f: 
     print " ".join([str(int(i)-1) for i in line.split()]) 

nadzieję, że pomoże

+0

Masz rację. Odpowiedź zaktualizowana – inspectorG4dget

2

Innym sposobem jest użycie modułu CSV i listowych:

from csv import reader 

data = [[int(j) - 1 for j in i] for i in reader(open("your_file"), delimiter=' ')] 

Powoduje to na przykład wykorzystanie twoich danych:

[[3, 1], [5, 4, 0], [8, 3, 4]] 
Powiązane problemy