2010-01-12 4 views
1

J'ai un énorme fichier texte, qui est structuré comme:Bash ou Python pour extraire des blocs de fichiers texte

SEPARATOR 
STRING1 
(arbitrary number of lines) 
SEPARATOR 
... 
SEPARATOR 
STRING2 
(arbitrary number of lines) 
SEPARATOR 
SEPARATOR 
STRING3 
(arbitrary number of lines) 
SEPARATOR 
.... 

Qu'est-ce que les changements entre les différents « blocs » du fichier est la chaîne et le contenu entre le séparateur. Je dois obtenir un script bash ou python qui donne un STRING_i dans l'entrée, donne en sortie un fichier qui contient

SEPARATOR 
STRING_i 
(number of lines for this string) 
SEPARATOR 

Quelle est la meilleure approche ici pour utiliser bash ou python? Une autre option? Ça doit aussi être rapide.

Merci

Répondre

3

En Python 2.6 ou mieux:

def doit(inf, ouf, thestring, separator='SEPARATOR\n'): 
    thestring += '\n' 
    for line in inf: 
    # here we're always at the start-of-block separator 
    assert line == separator 
    blockid = next(inf) 
    if blockid == thestring: 
     # found block of interest, use enumerate to count its lines 
     for c, line in enumerate(inf): 
     if line == separator: break 
     assert line == separator 
     # emit results and terminate function 
     ouf.writelines((separator, thestring, '(%d)' % c, separator)) 
     inf.close() 
     ouf.close() 
     return 
    # non-interesting block, just skip it 
    for line in inf: 
     if line == separator: break 

Dans les versions de Python plus anciens, vous pouvez faire presque la même , mais modifiez la ligne blockid = next(inf) à blockid = inf.next().

Les hypothèses ici sont que les fichiers d'entrée et de sortie sont ouverts par l'appelant (qui passe aussi dans les valeurs intéressantes de thestring, et éventuellement separator), mais il est le travail de cette fonction pour les fermer (par exemple, pour la facilité d'utilisation maximale comme un filtre de canalisation, avec inf de sys.stdin et ouf de sys.stdout); facile à modifier si nécessaire, bien sûr. La suppression des assert va accélérer le microscopique, mais j'aime leur rôle de "vérification de la santé" (et ils peuvent aussi aider à comprendre la logique du flux de code).

La clé de cette approche est qu'un fichier est un iterator (de lignes) et itérateurs peut être avancée à plusieurs endroits (afin que nous puissions avoir plusieurs for déclarations ou spécifique « faire avancer l'itérateur » appels tels que next(inf), et ils coopérer correctement).

0

j'utiliser Python et d'écrire quelque chose de similaire à ceci:

import sys 

file = open("file", "r") 
counter = 0 
count = False 
for line in file: 
    if count: 
    counter += 1 
    if count and SEPARATOR == line: 
    break 
    if not count and sys.argv[1] == line: 
    count = True 
print SEPARATOR, sys.argv[1], counter, SEPARATOR 
file.close() 
0

Si vous voulez que ce soit rapide, vous devez éviter de lire tout le fichier pour trouver le bloc de données dont vous avez besoin.

  1. lu sur le fichier une fois et mémoriser un index de a) décalage d'octet pour le début de chaque STRING_I et b) la longueur (en octets) du bloc - distance à l'autre SEPARATOR en octets. Vous pouvez stocker cet index dans un fichier séparé ou dans une « tête » du fichier en cours
  2. pour chaque requête STRING_I - lire dans l'index
 
    if STRING_I in index: 
    file.seek(start_byte_location) 
    file.read(length) 
    return parse_with_any_of_procedures_above # like @gruszczy's doit() but w/o loop 

ne vont pas par-dessus bord avec l'index: utilisez un dict de STRING_I -> (emplacement, longueur), et simplement simplejson/pickle dans un fichier

0

Vous pouvez utiliser (g) awk, qui est un outil relativement rapide pour traiter les fichiers.

read -p "Enter input: " input 
awk -vinput="$input" -vRS="SEPARATOR" '$0~input{ printf RT; print $0; printf RT }' file 
+0

salut, ça ne marche pas – user

Questions connexes