2012-05-05 27 views
5

Tengo dos archivos de texto en el siguiente formato:Procesamiento de texto con dos archivos

La primera es la siguiente en cada línea:

Key1:Value1

El segundo es éste:

Key2:Value2

¿Hay alguna manera de que pueda reemplazar Value1 en file1 por Value2 obtenido al usarlo como clave en file2?

Por ejemplo:

fichero1:

foo:hello 
bar:world 

fichero2:

hello:adam 
bar:eve 

me gustaría llegar:

foo:adam 
bar:eve 

No hay necesariamente una coincidencia entre los dos archivos en cada li nordeste. ¿Puede hacerse esto claramente en awk o algo, o debería hacerlo ingenuamente en Python?

Respuesta

3

Cree dos diccionarios, uno para cada archivo. Por ejemplo:

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

O si usted prefiere una sola línea:

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

entonces se podría hacer algo como:

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

Otra forma es que podría generar la clave-valor pares en reversa para file1 y use sets. Por ejemplo, si su archivo1 contiene foo:bar, su archivo1 dict es {bar: foo}.

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

Básicamente, usted puede encontrar rápidamente los elementos comunes usando intersección de conjuntos, por lo que esos elementos están garantizados para estar en archivo2 y no perder el tiempo la comprobación de su existencia.

Edit: Según lo señalado por @pepr Puede usar collections.OrderedDict para el primer método si el orden es importante para usted.

+2

Posiblemente el 'collections.OrderedDict' (Python 2.7+ y 3.1+) podría ser una opción para volver a escribir los valores en el archivo en el orden original (si se va a escribir de nuevo). [No me gusta el nombre ** fileX ** dado a un diccionario. Además, un archivo abierto siempre debe cerrarse antes que en tiempo de ejecución.] – pepr

+0

Buen punto, no había pensado en el pedido. – spinlok

0

Una vez que tenga:

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

Usted puede hacer un feo un trazador de líneas:

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'} 

Al igual que en el ejemplo está utilizando tanto el keys y values de file1keys como en file2.

0

Si no considera usar los comandos básicos de Unix/Linux haciendo trampa, entonces aquí hay una solución que usa pegar y awk.

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

+0

Esta solución asume que el dato clave en 'archivo1' se encuentra en el mismo número de línea de ese archivo que el número de línea en' archivo2' donde ocurre la referencia. Es razonable suponer que esto es cierto solo por coincidencia a en los pequeños datos de muestra dados. – Kaz

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

Los archivos de entrada, que deben seleccionarse en el campo que se unen sucesivamente.

Las opciones:

  • -t : - Use dos puntos como delimitador
  • -1 2 - Join en el campo 2 de archivo de 1
  • -2 1 - Join en el campo 1 del archivo de 2
  • -o 0 2.2 - Salga del campo de unión seguido del campo 2 del archivo2 (separado por el carácter del delimitador)
  • -a 2 - Salida de líneas sin unir de fichero2
2

La solución awk:

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

Esto podría funcionar para usted (probablemente sed de GNU):

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) 

Run:

$ txr subst.txr 
foo:adam 
bar:eve 
Cuestiones relacionadas