2012-05-05 6 views
5

mam dwa pliki tekstowe w następującym formacie:przetwarzanie tekstu z dwóch plików

Pierwszym z nich jest to w każdej linii:

Key1:Value1

Drugie jest to:

Key2:Value2

Czy istnieje sposób, aby wymienić Value1 w file1 przez Value2 uzyskane z użycia go jako klucza w file2?

Na przykład:

plik1:

foo:hello 
bar:world 

plik2:

hello:adam 
bar:eve 

chciałbym dostać:

foo:adam 
bar:eve 

Nie jest koniecznie mecz pomiędzy dwa pliki na każdym li ne. Czy można to zrobić dokładnie w awk lub czymś, czy też powinienem zrobić to naiwnie w Pythonie?

Odpowiedz

3

Utwórz dwa słowniki, po jednym dla każdego pliku. Na przykład:

file1 = {} 
for line in open('file1', 'r'): 
    k, v = line.strip().split(':') 
    file1[k] = v 

Lub jeśli wolisz jedno-liner:

file1 = dict(l.strip().split(':') for l in open('file1', 'r')) 

Następnie można zrobić coś takiego:

result = {} 
for key, value in file1.iteritems(): 
    if value in file2: 
     result[key] = file2[value] 

Innym sposobem jest można wygenerować klucz-wartość paruje w odwrotnej kolejności dla plików1 i zestawów użytkowych. Na przykład, jeśli plik1 zawiera foo:bar, twój plik1 dykt to {bar: foo}.

for key in set(file1) & set(file2): 
    result[file1[key]] = file2[key] 

Zasadniczo, można szybko znaleźć wspólne elementy za pomocą SET skrzyżowanie, więc te elementy są gwarancją w plik2 i nie tracić czasu na sprawdzanie ich istnienia.

Edit: Jak podkreślił @pepr Można użyć collections.OrderedDict do pierwszej metody, jeżeli zamówienie jest dla Ciebie ważne.

+2

Prawdopodobnie "collections.OrderedDict" (Python 2.7+ i 3.1+) może być opcją do zapisania wartości z powrotem do pliku w oryginalnej kolejności (jeśli ma być odesłana). [Nie podoba mi się nazwa ** fileX ** nadana słownikowi. Ponadto otwarty plik powinien zawsze zostać zamknięty wcześniej niż w środowisku wykonawczym.] – pepr

+0

Dobrze, nie myślałem o zamówieniu. – spinlok

0

Gdy masz:

file1 = {'foo':'hello', 'bar':'world'} 
file2 = {'hello':'adam', 'bar':'eve'} 

Można zrobić brzydki jeden liner:

print dict([(i,file2[i]) if i in file2 else (i,file2[j]) if j in file2 else (i,j) for i,j in file1.items()]) 
{'foo': 'adam', 'bar': 'eve'} 

Jak w przykładzie używasz zarówno na keys i values o file1 jak keys w file2.

0

Jeśli nie myślisz o używaniu podstawowych poleceń systemu Unix/Linux, to użyj rozwiązania wklej i awk.

paste file1.txt file2.txt | awk -F ":" '{ print $1":"$3 }'

+0

To rozwiązanie zakłada, że ​​wpisany plik danych w pliku 'plik1' znajduje się na tym samym numerze wiersza tego pliku, co numer wiersza w pliku' plik2', w którym występuje odwołanie. Rozsądnie jest przyjąć, że jest to prawdą tylko przez zbieg okoliczności w podanych małych próbkach danych. – Kaz

1
join -t : -1 2 -2 1 -o 0 2.2 -a 2 <(sort -k 2 -t : file1) <(sort file2) 

pliki wejściowe muszą być sortowane na polu są one połączone na.

Opcje:

  • -t : - Za pomocą dwukropka jako separatora
  • -1 2 - dołącz na polu 2 pliku 1
  • -2 1 - Zarejestrowany na polu 1 pliku 2
  • -o 0 2.2 - Wyprowadź pole łączenia, a następnie pole 2 z pliku2 (oddzielone znakiem separatora)
  • -a 2 - Dane wyjściowe bez linii z plik2
2

Rozwiązanie awk:

awk ' 
    BEGIN {FS = OFS = ":"} 
    NR==FNR {val[$1] = $2; next} 
    $1 in val {$2 = val[$1]} 
    {print} 
}' file2 file1 
0

To może pracować dla Ciebie (prawdopodobnie GNU sed):

sed 's#\([^:]*\):\(.*\)#/\\(^\1:\\|:\1$\\)/s/:.*/:\2/#' file2 | sed -f - file1 
0

TxR:

@(next "file2") 
@(collect) 
@key:@value1 
@ (cases) 
@ (next "file1") 
@ (skip) 
@value2:@key 
@ (or) 
@ (bind value2 key) 
@ (end) 
@ (output) 
@value2:@value1 
@ (end) 
@(end) 

Uruchom:

$ txr subst.txr 
foo:adam 
bar:eve