Aqui está outra abordagem: isso usa alguns sed
s:
an='[:alnum:]' esc=$(printf '3\[')
sed "/[${an}]/!d;=;a\ }
s/.*/ & /;s/[^${an}]\{1,\}/ /g
s| \([${an}"']\{1,\}\) | \
s/\([^+'"${an}"']\)\(\)\([^+'"${an}"']\)/\1+\2+\3/2|g
' <text |
sed '/^ /!N;s/\n */{/' |
sed -e 's/.*/ & /;s/+/ & /g' \
-f - \
-e "s/ //;s/ $//
s/+[^+ ]\{1,\}+/${esc}38;5;35m&${esc}0m/g
s/ + /+/g" text
Basicamente, os dois primeiros sed
s se unem para escrever um script para o terceiro. O primeiro sed
limpa tudo menos caracteres alfanuméricos de cada linha - e pula toda a linha sem um. Para todos os grupos de caracteres que permanecem, ele escreve uma declaração de substituição de que o terceiro acabará por ler ( e interpretar como seu script.
O segundo sed
é necessário porque o primeiro escreve seu script por linha - e cada linha pode ter várias instruções s///
. O primeiro imprime seu número de linha para cada linha que contém um alfanumérico, mas que precisa ser emparelhado em um contexto de função para o terceiro sed
- e assim o segundo faz isso.
Aqui está uma amostra de como o script se parece:
...
43{
s/\([^+[:alnum:]]\)\(n\)\([^+[:alnum:]]\)/++/2
s/\([^+[:alnum:]]\)\(N\)\([^+[:alnum:]]\)/++/2
s/\([^+[:alnum:]]\)\(G\)\([^+[:alnum:]]\)/++/2
}
44{
s/\([^+[:alnum:]]\)\(b\)\([^+[:alnum:]]\)/++/2
s/\([^+[:alnum:]]\)\(block\)\([^+[:alnum:]]\)/++/2
}
45{
s/\([^+[:alnum:]]\)\(END\)\([^+[:alnum:]]\)/++/2
s/\([^+[:alnum:]]\)\(SEDSCRIPT\)\([^+[:alnum:]]\)/++/2
}
Existe um 2
para cada s///
- isto porque cada substituição é direcionada para a segunda ocorrência de cada padrão - se uma segunda ocorrência não existir, nada é substituído. O acima é o resultado de executá-lo em outro dos meus scripts sed
- parece bastante imune a caracteres especiais ou similares.
Como eu estava escrevendo, descobri que era mais fácil dizer o que estava acontecendo se eu colori sua seleção - que é o que ...
s/+[^+ ]\{1,\}+/${esc}38;5;35m&${esc}0m/g
... essa linha faz. Você pode comentar ou removê-lo sempre que você usa isso e não quer ou precisa dele.
Aqui está o script que ele escreve para seus dados de exemplo:
1{
s/\([^+[:alnum:]]\)\(qq\)\([^+[:alnum:]]\)/++/2
s/\([^+[:alnum:]]\)\(ab\)\([^+[:alnum:]]\)/++/2
s/\([^+[:alnum:]]\)\(xyz\)\([^+[:alnum:]]\)/++/2
s/\([^+[:alnum:]]\)\(ab\)\([^+[:alnum:]]\)/++/2
s/\([^+[:alnum:]]\)\(qq\)\([^+[:alnum:]]\)/++/2
s/\([^+[:alnum:]]\)\(aa\)\([^+[:alnum:]]\)/++/2
s/\([^+[:alnum:]]\)\(ab\)\([^+[:alnum:]]\)/++/2
}
Veja o que é impresso:
qq ab xyz +ab+ +qq+ aa +ab+
E de alguns dos meus sed
script de antes:
s/\(\(.\)${bs}\)\{1,\}/${esc}38;5;35m&${+esc+}0m/g
s/\(_${bs}[^_]\)\{1,\}/${esc}38;5;75m&${+esc+}0m/g
s/.${bs}//g
s/\(\(${esc}\)0m[^m]*+m+[_ ]\{,+2+\}\)\{+2+\}/_/g
n; /./!N;G