search replace com exceção de aspas

6

Eu tenho o seguinte texto que eu preciso substituir todo o espaço em branco com alimentação de linha, exceto qualquer coisa entre aspas.

ENTRADA

This is an example text with    some      spaces.
This should be 2nd line.
However the spaces between "quotes    should not    change".
last line

A saída deve ser semelhante a esta:

This
is
an
example
text
with    
some
spaces.
This
should
be
2nd
line.
However
the
spaces
between
"quotes    should not    change".
last
line

Eu tentei usar o awk / sed / perl, mas não consegui colocar nada, exceto as aspas.

O texto citado não ultrapassará mais de uma linha.

    
por Raza 16.11.2017 / 21:48

3 respostas

5

Usando o GNU-grep:

grep -Po '(".*?"|\S)+' file.txt
    
por 17.11.2017 / 01:42
5

EDITAR: Minha solução foi um exagero total. Eu não sei o que eu estava pensando. O problema pode ser resolvido por uma expressão regular extremamente simples. Consulte a solução enviada por JJoao .

A biblioteca Python shlex quase faz isso pronto para uso. Aqui está um script de exemplo:

#!/usr/bin/env python2
# -*- coding: ascii -*-
"""tokens.py"""

import sys
import shlex

with open(sys.argv[1], 'r') as textfile:
    text = ''.join(textfile.readlines())
    for token in shlex.split(text, posix=False):
        print(token)

Se seus dados estiverem no arquivo data.txt (por exemplo), você poderá executá-lo assim:

python tokens.py data.txt

E aqui está a saída que produz:

This
is
an
example
text
with
some
spaces.
This
should
be
2nd
line.
However
the
spaces
between
"quotes    should not    change"
.
last
line

Observe que ele coloca o período em uma linha separada. Isso ocorre porque termina os tokens nas cotações de fechamento. Como o exemplo que você deu não parece exigir cadeias de caracteres com múltiplas linhas ou caracteres com escape, provavelmente não é difícil criar seu próprio lexer. Aqui está o que eu criei:

#!/usr/bin/env python2
# -*- coding: ascii -*-
"""tokens.py"""

import sys

def tokenize(string):
    """Break a string into tokens using white-space as the only delimiter
    while respecting double-quoted substrings and keeping the double-quote
    characters in the resulting token."""

    # List to store the resulting list of tokens
    tokens = []

    # List to store characters as we build the current token
    token = []

    # Flag to keep track of whether or not
    # we're currently in a quoted substring
    quoted = False

    # Iterate through the string one character at a time
    for character in string:

        # If the character is a space then we either end the current
        # token (if quoted is False) or add the space to the current
        # token (if quoted is True)
        if character == ' ':
            if quoted:
                token.append(character)
            elif token:
                tokens.append(''.join(token))
                token = []

        # A double-quote character is always added to the token
        # It also toggles the 'quoted' flag
        elif character == '"':
            token.append(character)
            if quoted:
                quoted = False
            else:
                quoted = True

        # All other characters are added to the token
        else:
            token.append(character)

    # Whatever is left at the end becomes another token
    if token:
        tokens.append(''.join(token))

    # Return the resulting list of strings
    return(tokens)

if __name__=="__main__":
    """Read in text from a file and pring out the resulting tokens."""
    with open(sys.argv[1], 'r') as textfile:
        text = ''.join(textfile.readlines()).replace("\n", " ")
        for token in tokenize(text):
            print(token)

Isso produz exatamente os resultados que você pediu. Você provavelmente poderia implementar esse algoritmo em outro idioma (como o Perl) facilmente. Por acaso estou mais confortável com o Python.

    
por 16.11.2017 / 22:21
0

Se linhas vazias do texto original puderem ser removidas:

sed -r 's/("[^"]*"[^ ]?)/\n\n/g' input.txt |
sed -r '/^"/!s/\s{1,}/\n/g' |
sed '/^$/d'

Se linhas vazias do texto original devem ser preservadas:

sed -r 's/("[^"]*"[^ ]?)/###\n\n###/g' input.txt |
sed -r '/^"/!s/\s{1,}/\n/g' |
sed '/###/d'

Entrada (complicada para o teste)

This is an "example text" with    some      spaces.
This should be 2nd line.
"However the spaces" between "quotes    should not    change".
"last line"

Saída

This
is
an
"example text"
with
some
spaces.
This
should
be
2nd
line.
"However the spaces"
between
"quotes    should not    change".
"last line"
    
por 17.11.2017 / 01:39