Preciso extrair cadeias de texto de um único arquivo contendo uma linha muito longa de texto sem delimitadores. Usando a linha de amostra abaixo, estes são os seguintes fatos conhecidos:
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
entalhes
fonte
fonte
Respostas:
E se grep
Isso imprime cada registro de cada tipo de registro em uma linha separada. Para redirecionar
grep
a saída para 3 arquivos nomeadosA1
,B1
,C1
respectivamente,fonte
Aqui está uma solução possível usando o FPAT de gawk
Como uma linha:
fonte
FPAT
requer a versãoEm Perl:
Invoque-o como:
Código testado e funciona com a sua entrada.
Atualizar
Nos seus comentários, você solicitou um "equivalente Unix" acima. Eu duvido muito que exista isso, pois a expressão Perl usada para analisar sua linha é uma expressão altamente irregular e duvido que expressões regulares de baunilha possam analisar seu formato de dados: é muito semelhante a um tipo famoso de expressão que regex pode 't analisar (corresponde a qualquer número de
a
' s seguido pelo mesmo número deb
's).De qualquer forma, a abordagem "Unix" mais próxima que posso encontrar é a generalização da resposta do 1_CR . Você deve observar que essa abordagem é específica para a implementação do GNU
grep
e, portanto, não funcionará na maioria dos Unices. A abordagem Perl, pelo contrário, deve funcionar da mesma maneira em qualquer plataforma na qual o Perl trabalha. Aqui está minhagrep
abordagem GNU sugerida :Atualizar
Com base nas solicitações do OP nos comentários, em vez de passar o nome do arquivo como argumento da linha de comando, ele pode ser aberto no script da seguinte maneira:
Isso pressupõe que você tenha declarado que a variável
$input_file_name
contém, bem, o nome do arquivo de entrada.Quanto a acrescentar um carimbo de data / hora ao nome do arquivo de saída, você pode usar a
qx{}
sintaxe: entre chaves, você pode colocar qualquer comando Unix que desejar, e ele será executado e sua saída padrão será lida no lugar doqx{}
operador:O
qx
operador não está restrito a chaves, use seu personagem favorito como delimitador, apenas verifique se ele não está no comando que você precisa executar:e assim por diante...
Em algum código Perl, você pode ver os backticks (
` `
) usados para servir essa função, semelhante ao que o shell faz. Pense noqx
operador como a generalização dos backticks para qualquer delimitador.A propósito, isso fornecerá um registro de data e hora ligeiramente diferente para cada arquivo (se a diferença de seus tempos de criação for um número finito de segundos). Se você não quiser isso, poderá fazê-lo em duas etapas:
fonte