Extraindo padrão de várias linhas

3

Eu tenho um arquivo test.tex com conteúdo semelhante a este:

\documentclass{scrartcl}
\usepackage{graphicx}
\title{Test}
\author{Author 1, Author 2, Author 3}
\begin{document}
\end{document}

Eu quero extrair todos os autores que estão escritos no { ... } . Por isso fiz o seguinte:

authors=$(cat test.tex | grep '\author' | tr -d '\author' | tr -d '{' | tr -d '}' )

Este código funciona apenas para este caso. Meu problema é que

  1. pode haver [] em vez de {}
  2. a linha pode se estender por várias linhas, como no exemplo a seguir

\author{Author 1,

Author 2,

Author 3}

Alguém sabe como resolver esses dois problemas?

    
por ADDB 15.07.2017 / 16:37

4 respostas

2
#!/bin/bash

sed -nr '
/\author/ {
    :ending
    /]|}$/! {
        N   
        b ending 
    }
    s/\author(\{|\[)(.*)(}|])//p
}
' test.tex

Explicação (código do mesmo, mas comentários adicionados):

#!/bin/bash

sed -nr '
# if the line contains the \author string, we are working with it.
/\author/ {

    ##### this part are needed for multiple line pattern processing

    # put a label here. We will be return to this point, 
    # until we reach line, which have } or ] in the ending.
    :ending

    # if this line does not ended by } or ]. 
    # It is tell us, that this line continues on the next line.
    /]|}$/! {

        # Take the next line and append it to the previous line. 
        # Just join them together.
        N   

        # Go to the ":ending" label
        b ending 
    }

    ##### ending multiple line pattern processing

    # remove the \author word and brackets from line
    s/\author(\{|\[)(.*)(}|])//p
}
' test.tex

test.tex

\documentclass{scrartcl}
\usepackage{graphicx}
\title{Test}
\author{Author 1, Author 2, Author 3}
\author[Author 1, Author 2, Author 3]
\author{Author 1,
Author 2,
Author 3}
\author[Author 1,
Author 2,
Author 3]
\begin{document}
\end{document}

saída

Author 1, Author 2, Author 3
Author 1, Author 2, Author 3
Author 1,
Author 2,
Author 3
Author 1,
Author 2,
Author 3
    
por 15.07.2017 / 21:22
3
grep -zPo '\author{\K[^}]*' ex1.tex | tr '
grep -zPo '\author{\K[^}]*' ex1.tex | tr '%pre%\n' '\n '
\n' '\n '

Algumas notas rápidas de explicação:

  • -z registros de entrada e saída ("linhas") são separados por NULL ( -P ). Então, o arquivo TeX completo será um único registro.
  • -o Use a variante de expressão regular Perl pcre.
  • \author{\K imprime apenas a parte do registro que corresponde ao regExp.
  • tr '\n\n' '\n ' significa contexto à esquerda

O \n altera o separador de registro de saída ( to %code% ) e remove NewLines dentro dos nomes ( %code% to %code% )

    
por 15.07.2017 / 17:27
2

Isso parece fazer o trabalho: egrep -o '[\[{]?Author' | sed -E 's/[\[{]//'

Exemplos:

1)

echo "\documentclass{scrartcl}
\usepackage{graphicx}
\title{Test}
\author[Author 1,
Author 2
Author 3 ] " | egrep -o '[\[{]?Author' | sed -E 's/[\[{]//'
Author
Author
Author

2)

echo "\documentclass{scrartcl}
\usepackage{graphicx}
\title{Test}
\author[Author 1, Author 2, Author 3]
\begin{document}
\end{document}" | egrep -o '[\[{]?Author' | sed -E 's/[\[{]//'
Author
Author
Author

3)

echo "\documentclass{scrartcl}
\usepackage{graphicx}
\title{Test}
\author{Author 1, Author 2, Author 3}
\begin{document}
\end{document}" | egrep -o '[\[{]?Author' | sed -E 's/[\[{]//'
Author
Author
Author

Você provavelmente pode fazer isso usando apenas grep e lookbehinds e outros. Eu pessoalmente não tenho problemas em usar um pipe em sed após grep .

    
por 15.07.2017 / 17:14
2

Python

Com o seu arquivo de entrada como determinado na pergunta, um liner pode ser feito da seguinte forma:

$ python -c 'import sys,re;f=open(sys.argv[1],"r");a=tuple(l for l in f.readlines() if l.startswith("\author") );print("\n".join(re.split(", |,|{|}",a[0].strip())[1:]))' input.tex      
Author 1
Author 2
Author 3

E um script assim:

#!/usr/bin/env python

import sys,re

# read the doc, find the desired line
line=""
with open(sys.argv[1]) as f:
    for l in f:
        if l.startswith("\author"):
            line=l.strip()
            break
# split at multiple separators, get slice of that list starting since 2nd item
author_list = re.split( ", |,|{|}", line )[1:] 
# print 1 author per line
print("\n".join(author_list))

As etapas principais são duplicadas - leia o arquivo e localize a linha que estrela com \authors string e, em seguida, divida a linha em vários separadores em uma lista de tokens e crie uma nova string separada da linha dessa lista de fichas. Eu também tomei a liberdade de considerar a possibilidade de você ter que dividir em , ou ,<space> .

    
por 16.07.2017 / 04:13