Processamento de texto - Como obter o padrão Uma linha correspondente até a primeira ocorrência da linha de correspondência do padrão B?

1

Eu quero obter as linhas que, em ordem inversa, coincidam da linha de correspondência padrão A com a primeira ocorrência da linha de correspondência padrão B junto com as linhas que ela passa.

ATUALIZADO: example_file.txt

ISA*00*          *00*          *ZZ*SIX-SIX6      *12*666666666666     *66666666*6666*U*666666666*6666666666*0*P*\
GS*FA*SIX-SIX-SIX*666666666*6666666*6666*6666*X*66666
ST*666*666
AK1*SX*666
AK2*777*6666666
AK5*A
AK2*777*7777777
AK3*S6*5**3
AK3*A2*5**3
AK4*3*6969*4
AK4*7*6969*4
AK5*R*5
AK2*777*6666666
AK5*A
AK2*777*69696969
AK3*J7*5**3
AK4*3*6969*4
AK5*R*5
AK9*P*20*20*19
SE*69*6969
GE*1*6767
IEA*1*0000000000

O que eu quero é obter, de baixo para cima, todo o padrão AK5 com R depois disso, assim:

Padrão A : AK5*R

e faça com que todas as linhas subam até que a primeira ocorrência do padrão B seja correspondida. por exemplo:

Padrão B : AK2

Saída desejada :

O primeiro padrão A será chamado E1

AK2*777*7777777
AK3*S6*5**3
AK3*A2*5**3
AK4*3*6969*4
AK4*7*6969*4
AK5*R*5

ATUALIZADO: O segundo padrão A correspondido será chamado E2

AK2*777*69696969
AK3*J7*5**3
AK4*3*6969*4
AK5*R*5

e assim por diante, se houver mais de um padrão A correspondente.

EDITAR: Eu sei que sed pode fazer isso mas ainda não tenho sorte em obter a linha de cada padrão A corresponde à primeira ocorrência do padrão B correspondido e armazená-los em um arquivo de texto temporário para continuar o processo.

Este é o comando sed do meu exemplo que obtém todos os padrões disponíveis B no example_file.txt

sed -ne '/AK2\*/,/\AK5\*R/p' example_file.txt

Exemplo de cenário lógico de comando:

A="AK5\*R"
B="AK2"

find the first $A < example_file.txt; # AK5\*R
move to previous line until first occurrence of $B line; # AK2*any_number*any_number
get all lines from first $A to its first occurrence of $B and store in a text file; # result > e1.txt
# The same way goes to the second occurrence of pattern A.

(NOTA: Primeira ocorrência de $ B, a partir de cada linha $ A recebe $ A e as linhas anteriores até a primeira linha $ B correspondente. Assim, por exemplo, se a primeira linha $ A começa no meio linha de um arquivo como na linha número 50, se o arquivo tiver 100 linhas no total, então vá para a linha anterior até que o comando encontre a primeira linha $ B que ele vê.) Veja o exemplo abaixo.

example_file2.txt

ISA*00*          *00*          *ZZ*SIX-SIX6      *12*666666666666     *66666666*6666*U*666666666*6666666666*0*P*\
GS*FA*SIX-SIX-SIX*666666666*6666666*6666*6666*X*66666
ST*666*666
AK1*SX*666
AK2*777*6666666
AK5*A
AK2*777*7777777
AK5*A
AK2*777*888888
AK5*A
AK2*777*7777777
AK5*A
AK2*777*5555555
AK5*A
AK2*777*7777777
AK5*A
AK2*777*4545435
AK5*A
AK2*777*7777777
AK5*A
AK2*777*7777777
AK3*S6*5**3
AK3*A2*5**3
AK4*3*6969*4
AK4*7*6969*4
AK5*A
AK2*777*0987654
AK3*S6*5**3
AK3*A2*5**3
AK4*3*6969*4
AK4*7*6969*4
AK5*R*5
AK2*777*7777777
AK3*S6*5**3
AK3*A2*5**3
AK4*3*6969*4
AK4*7*6969*4
AK5*A
AK2*777*7777777
AK3*S6*5**3
AK3*A2*5**3
AK4*3*6969*4
AK4*7*6969*4
AK5*A

Saída:

AK2*777*0987654
AK3*S6*5**3
AK3*A2*5**3
AK4*3*6969*4
AK4*7*6969*4
AK5*R*5
    
por WashichawbachaW 08.02.2018 / 11:07

2 respostas

1

Leitura novamente sua descrição Eu entendo que você deseja que o primeiro jogo do padrão B de baixo para cima até que (a subir) na primeira partida do padrão A. Mas as seções resultantes devem ser na ordem em que o arquivo tem.

Isso requer muita lógica. O seguinte script shell faz tudo. Vai colocar os resultados na ordem interna correta nos arquivos E e algum número, primeiro arquivo ( E1 ) terá o primeiro jogo a partir do topo, último arquivo terá a última seção de jogo.

#!/bin/bash

rm -rf resE* E*

tac ../example_file.txt |
    awk 'BEGIN{i=1}
         /^AK5\*R.*/{p=1}
         {if(p==1){f="resE" i;print($0)>>f;close(f)}}
         /^AK2.*/{if(p==1){i++};p=0}
        '
set -- resE* 
c=$#
for (( i=1;i<=$c;i++)); do
    pos=$(($c-$i+1))
    [ -f "$1" ] && tac "$1" > "E$pos"
    shift
done

Os intervalos resultantes serão:

$ cat E1
AK2*777*7777777
AK3*S6*5**3
AK3*A2*5**3
AK4*3*6969*4
AK4*7*6969*4
AK5*R*5

$ cat E2
AK2*777*7777777
AK3*J7*5**3
AK4*3*6969*4
AK5*R*5
    
por 08.02.2018 / 19:11
1

POSIX ex para o resgate novamente!

ex é o editor de arquivos com script especificado pelo POSIX. Para qualquer coisa envolvendo backwards addressing, geralmente é uma solução muito melhor do que Awk ou Sed.

O seguinte one-liner funciona perfeitamente no seu example_file2.txt :

printf '%s\n' 'g/AK5[*]R/?AK2?,.p' | ex example_file.txt

No seu example_file.txt , ele também funciona, mas como o comando g lobal em ex não pode gravar em um destino separado para cada intervalo aplicado, os dois arquivos de saída desejados são mesclados da seguinte forma:

AK2*777*7777777
AK3*S6*5**3
AK3*A2*5**3
AK4*3*6969*4
AK4*7*6969*4
AK5*R*5
AK2*777*69696969
AK3*J7*5**3
AK4*3*6969*4
AK5*R*5

No entanto, isso é fácil de manusear - com outra ferramenta POSIX, csplit , projetada para dividir arquivos de acordo com um "contexto".

Solução POSIX portátil:

patA='AK5[*]R'
patB='AK2'

printf '%s\n' "g/$patA/?$patB?,.p" |
  ex example_file.txt |
  csplit -f my_unique_prefix_ -n 1 -s -k - "/$patB/" '{999}'

for f in my_unique_prefix_*; do
  mv "$f" "e${f##my_unique_prefix_}.txt";
done

rm e0.txt

Existe um elemento final para tornar esta uma solução perfeita, que é renumerar os arquivos em ordem inversa. Eu não fiz essa parte.

Se você não se importa com a numeração dos arquivos na mesma ordem do arquivo, e se não se importa se a extensão .txt foi omitida e se você não se importa se os arquivos foram numerados de e01 em vez de e1 , e se você não se importa em imprimir uma mensagem de diagnóstico sobre quantas linhas foram colocadas em cada arquivo, podemos simplificar:

patA='AK5[*]R'
patB='AK2'

printf '%s\n' "g/$patA/?$patB?,.p" |
  ex example_file.txt |
  csplit -f e -k - "/$patB/" '{999}'

rm e00
    
por 09.02.2018 / 04:39