Necesito extraer cadenas de texto de un solo archivo que contiene una línea de texto muy larga sin delimitadores. Usando la siguiente línea de muestra, estos son los siguientes hechos conocidos:
??????? 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
fuente
fuente
Respuestas:
Qué tal si grep
Esto imprime cada registro de cada tipo de registro en una línea separada. Para redirigir
grep
la salida a 3 archivos con el nombreA1
,B1
,C1
respectivamente,fuente
Aquí hay una posible solución usando FPAT de gawk
Como una línea:
fuente
FPAT
requiere Gawk versión 4. Ver: linuxjournaldigital.com/linuxjournal/201109#pg98En perl:
Invocarlo como:
Código probado y funciona con su entrada dada.
Actualizar
En sus comentarios, solicitó un "equivalente de Unix" de lo anterior. Dudo mucho que exista tal cosa, ya que la expresión Perl utilizada para analizar su línea es una expresión muy irregular y dudo que las expresiones regulares vainilla puedan analizar su formato de datos dado: es demasiado similar a un tipo famoso de expresión que regex puede 't parse (coincide con cualquier número de
a
' s seguido por el mismo número deb
's).En cualquier caso, el enfoque "Unix" más cercano que puedo encontrar es la generalización de la respuesta de 1_CR . Debe tener en cuenta que este enfoque es específico para la implementación de GNU
grep
y, por lo tanto, no funcionará en la mayoría de los Unices. El enfoque de Perl, por el contrario, debería funcionar igual en cualquier plataforma en la que Perl trabaje. Aquí está migrep
enfoque sugerido de GNU :Actualizar
Según las solicitudes del OP en los comentarios, en lugar de pasar el nombre del archivo como un argumento de línea de comando, se puede abrir dentro del script de la siguiente manera:
Esto supone que ha declarado que la variable
$input_file_name
contiene, bueno, el nombre del archivo de entrada.En cuanto a agregar una marca de tiempo al nombre del archivo de salida, puede usar la
qx{}
sintaxis: entre las llaves puede colocar cualquier comando de Unix que desee y se ejecutará y su salida estándar se leerá en lugar delqx{}
operador:El
qx
operador no está restringido a llaves, use su personaje favorito como delimitador, solo asegúrese de que no esté en el comando que necesita ejecutar:y así...
En algunos códigos de Perl, puede ver backticks (
` `
) utilizados para servir esta función, similar a lo que hace el shell. Solo piense en elqx
operador como la generalización de los backticks a cualquier delimitador.Por cierto, esto le dará una marca de tiempo ligeramente diferente a cada archivo (si la diferencia de sus tiempos de creación es un número finito de segundos). Si no quieres esto, puedes hacerlo en dos pasos:
fuente