J'ai besoin d'extraire des chaînes de texte à partir d'un seul fichier contenant une très longue ligne de texte sans délimiteurs. En utilisant l'exemple de ligne ci-dessous, voici les faits connus suivants:
??????? A1XXXXXXXXXX ??????? B1XXXX ??????? A1XXXXXXXXXX ??????? C1XXXXXXX
1. It contains 38 fixed width record types
2. The record marker is a 7 alphanumeric character followed by, for example, ‘A1’.
3. Each record type has varying widths, for example, A1 record type will have 10 characters following it, if B1 then 4, and if C1 then 7.
4. The record types aren’t clumped together and can be in any order. As in the example, its A1,B1,A1,C1
5. The example above has 4 records and each record type needs to go to separate files. In this case 38 of them.
??????? A1XXXXXXXXXX
??????? B1XXXX
??????? A1XXXXXXXXXX
??????? C1XXXXXXX
6. The record identifier, e.g. ????????A1, can appear in the body of the record so cannot use grep.
7. With the last point in mind, I was proposing 3 solutions but not sure on how to script this and of course would greatly appreciate some help.
a. Traverse through the file from the beginning and sequentially strip out the record to the appropriate output file. For example, strip out first record type A1 to A1file which I know is 10 characters long then re-interrogate the file which will then have B1 which I know is 4 chars long, strip this out to B1file etc.. <<< this seems painful >>
b. Traverse through the file and append some obscure character to each record marker within the same file. Much like above but not strip out. I understand it still will use the same logic but seems more elegant
c. I did think of simply using the proposed grep -oE solution but then re-interrogate the output files to see if any of the 38 record markers exist anywhere other than at the beginning. But this might not always work.
text-processing
sed
awk
jags
la source
la source
Réponses:
Que diriez-vous grep
Cela imprime chaque enregistrement de chaque type d'enregistrement sur une ligne distincte. Pour rediriger la
grep
sortie 3 fichiers nommésA1
,B1
,C1
respectivement,la source
Voici une solution possible en utilisant FPAT de Gawk
En une ligne:
la source
FPAT
nécessite la version 4 de gawk. Voir: linuxjournaldigital.com/linuxjournal/201109#pg98En Perl:
Appelez-le comme:
Code testé et fonctionne avec votre entrée donnée.
Mise à jour
Dans vos commentaires, vous avez demandé un "équivalent Unix" de ce qui précède. Je doute fortement qu'il existe une telle chose, car l'expression Perl utilisée pour analyser votre ligne est une expression très irrégulière et je doute que les expressions régulières vanille puissent analyser votre format de données donné: il est trop similaire à un type d'expression célèbre que l'expression régulière peut 't parse (correspond à n'importe quel nombre de
a
' suivi du même nombre deb
').Dans tous les cas, l'approche "Unix" la plus proche que je puisse trouver est la généralisation de la réponse de 1_CR . Vous devez noter que cette approche est spécifique à l'implémentation GNU
grep
et ne fonctionnera donc pas sur la plupart des Unices. L'approche Perl, au contraire, devrait fonctionner de la même manière sur n'importe quelle plate-forme sur laquelle Perl fonctionne. Voici mongrep
approche GNU suggérée :Mise à jour
Sur la base des demandes de l'OP dans les commentaires, au lieu de passer le nom de fichier comme argument de ligne de commande, il peut être ouvert dans le script comme suit:
Cela suppose que vous avez déclaré que la variable
$input_file_name
contient, eh bien, le nom du fichier d'entrée.Quant à l'ajout d'un horodatage au nom du fichier de sortie, vous pouvez utiliser la
qx{}
syntaxe: entre les accolades, vous pouvez mettre n'importe quelle commande Unix que vous souhaitez et elle sera exécutée et sa sortie standard relue à la place de l'qx{}
opérateur:L'
qx
opérateur n'est pas limité aux accolades, utilisez votre caractère préféré comme délimiteur, assurez-vous simplement qu'il n'est pas dans la commande que vous devez exécuter:etc...
Dans certains codes Perl, vous pouvez voir des backticks (
` `
) utilisés à la place pour cette fonction, de la même manière que le shell.qx
Considérez simplement l' opérateur comme la généralisation des backticks à n'importe quel délimiteur.Soit dit en passant, cela donnera un horodatage légèrement différent à chaque fichier (si la différence de leurs temps de création se trouve être un nombre fini de secondes). Si vous ne le souhaitez pas, vous pouvez le faire en deux étapes:
la source