Como remover todos os espaços em branco apenas entre colchetes [] usando ferramentas Unix? [duplicado]

5

Replace text between brackets

Entrada

testing on Linux [Remove white space] testing on Linux

Saída

testing on Linux [Removewhitespace] testing on Linux

Então, como podemos simplesmente remover todo o espaço em branco entre os parênteses e alcançar a saída como determinado?

    
por ekassis 01.02.2013 / 12:33

3 respostas

6

Se o [ , ] estiver balanceado e não aninhado, você poderá usar o GNU awk como em:

gawk -v RS='[][]' '
   NR % 2 == 0 {gsub(/\s/,"")}
   {printf "%s", $0 RT}'

Isso é usar [ e ] como os separadores de registro em vez do caractere de nova linha e remover espaços em branco apenas em todos os outros registros.

Com sed, com o requisito adicional de que não haja caracteres de nova linha dentro de [...] :

sed -e :1 -e 's/\(\[[^]]*\)[[:space:]]//g;t1'

Se eles são balanceados, mas podem ser aninhados como em blah [blih [1] bluh] asd , então você pode usar os operadores de expressão regular de recursão de perl como:

perl -0777 -pe 's{(\[((?:(?>[^][]+)|(?1))*)\])}{$&=~s/\s//rsg}gse'

Outra abordagem, que seria dimensionada para arquivos muito grandes, seria usar o operador% regexp (?{...}) perl para acompanhar a profundidade do colchete, como em:

perl -pe 'BEGIN{$/=92}s{((?:\[(?{$l++})|\](?{$l--})|[^][\s]+)*)(\s+)}
  {"$1".($l>0?"":$2)}gse'

Na verdade, você também pode processar a entrada de um caractere de cada vez, como:

perl -pe 'BEGIN{$/=}if($l>0&&/\s/){$_=""}elsif($_ eq"["){$l++}elsif($_ eq"]"){$l--}'

Essa abordagem pode ser implementada com ferramentas POSIX:

od -A n -vt u1 |
  tr -cs 0-9 '[\n*]' |
  awk 'BEGIN{b[32]=""; b[10]=""; b[12]=""} # add more for every blank
       !NF{next}; l>0 && $0 in b {next}
       $0 == "91" {l++}; $0 == "93" {l--}
       {printf "%c", $0}'

Com sed (assumindo que não há nova linha dentro do [...] ):

sed -e 's/_/_u/g;:1' -e 's/\(\[[^][]*\)\[\([^][]*\)]/_o_c/g;t1' \
    -e :2 -e 's/\(\[[^]]*\)[[:space:]]//g;t2' \
    -e 's/_c/]/g;s/_o/[/g;s/_u/_/g'

São considerados espaço em branco acima de qualquer caractere de espaçamento horizontal (SPC, TAB) ou vertical (NL, CR, VT, FF ...) no conjunto de caracteres ASCII. Dependendo da sua localidade, outros podem ser incluídos.

    
por 01.02.2013 / 13:19
2

Solução Perl 5.14 (que é mais curta e o IMO é mais fácil de ler - especialmente se você formatá-la em várias linhas em um arquivo, em vez de em uma linha)

perl -pE 's{(\[ .*? \])}{$1 =~ y/ //dr}gex'

Isso funciona porque, no 5.14, o mecanismo de expressão regular é reentrante. Aqui está, expandido e comentado:

s{
    (\[ .*? \])         # search for [ ... ] block, capture (as $1)
}{
    $1 =~ y/ //dr       # delete spaces. you could add in other whitespace here, too
                        # d = delete; r = return result instead of modifying $1
}gex; # g = global (all [ ... ] blocks), e = replacement is perl code, x = allow extended regex
    
por 01.02.2013 / 13:17
0

Solução de Perl:

perl -pe 's/(\[[^]]*?)\s([^][]*\])/$1$2/ while /\[[^]]*?\s[^][]*\]/'
    
por 01.02.2013 / 12:50