Estou procurando uma maneira de substituir seqüências de caracteres de espaço reservado em um arquivo de modelo por valores concretos, por ferramentas comuns do Unix (bash, sed, awk, talvez perl). É importante que a substituição seja feita em uma única passagem, ou seja, o que já foi digitalizado / substituído não deve ser considerado para outra substituição. Por exemplo, essas duas tentativas falham:
echo "AB" | awk '{gsub("A","B");gsub("B","A");print}'
>> AA
echo "AB" | sed 's/A/B/g;s/B/A/g'
>> AA
O resultado correto neste caso é obviamente BA.
Em geral, a solução deve ser equivalente à varredura da entrada da esquerda para a direita para uma correspondência mais longa com uma das seqüências de substituição especificadas e, para cada correspondência, executando uma substituição e continuando a partir desse ponto na entrada (nenhuma das entrada já lida nem as substituições realizadas devem ser consideradas para correspondências). Na verdade, os detalhes não importam, apenas que os resultados da substituição nunca são considerados para outra substituição, no todo ou em parte.
NOTA Estou procurando apenas soluções genéricas corretas. Não proponha soluções que falhem para determinadas entradas (arquivos de entrada, pesquisa e substituição de pares), por mais improváveis que pareçam.
tr AB BA
.Respostas:
OK, uma solução geral. A seguinte função bash requer
2k
argumentos; cada par consiste em um espaço reservado e uma substituição. Cabe a você citar as seqüências de caracteres adequadamente para passá-las para a função. Se o número de argumentos for ímpar, será adicionado um argumento vazio implícito, que excluirá efetivamente as ocorrências do último espaço reservado.Nem os espaços reservados nem as substituições podem conter caracteres NUL, mas você pode usar
\
escapes C padrão , como\0
se você precisar deNUL
s (e, consequentemente, precisar escrever\\
se quiser\
).Requer as ferramentas de compilação padrão que devem estar presentes em um sistema semelhante ao posix (lex e cc).
Assumimos que
\
já está escapado, se necessário, nos argumentos, mas precisamos escapar de aspas duplas, se presente. É isso que o segundo argumento para o segundo printf faz. Como alex
ação padrão éECHO
, não precisamos nos preocupar com isso.Execução de exemplo (com horários para os céticos; é apenas um laptop barato):
Para entradas maiores, pode ser útil fornecer um sinalizador de otimização
cc
e, para compatibilidade atual com o Posix, seria melhor usarc99
. Uma implementação ainda mais ambiciosa pode tentar armazenar em cache os executáveis gerados em vez de gerá-los a cada vez, mas eles não são exatamente caros para gerar.Editar
Se você possui o tcc , pode evitar o incômodo de criar um diretório temporário e aproveitar o tempo de compilação mais rápido, o que ajudará em entradas de tamanho normal:
fonte
fn() { tcc ; } <<CODE\n$(gen code)\nCODE\n
. No entanto, posso perguntar - essa é uma resposta incrível e eu a votei assim que a li - mas não entendo o que está acontecendo com o array de shell? O que"${@//\"/\\\"}"
isso faz?Algo assim sempre substituirá cada ocorrência de suas sequências de destino apenas uma vez, uma vez que elas ocorrem
sed
no fluxo a uma mordida por linha. Esta é a maneira mais rápida que consigo imaginar. Então, novamente, eu não escrevo C. Mas isso não lidar de forma confiável delimitadores nulos se assim desejar. Veja esta resposta para saber como funciona. Isso não tem problemas com nenhum caractere shell especial ou similar contido - mas é específico da localidade ASCII ou, em outras palavras,od
não produzirá caracteres de vários bytes na mesma linha e fará apenas um por. Se este for um problema, você deverá adicionariconv
.fonte
sed
e economizar até um valor nulo ou algo assim, e entãosed
escrever esse script; ou colocá-lo em uma função shell e dar-lhe os valores em uma mordida por linha como"/$1/"
..."/$2/"
- talvez eu vou escrever essas funções também ...PLACE1
,PLACE2
ePLA
.PLA
ganha sempre. OP diz: "equivalente a digitalização da entrada da esquerda para a direita para um jogo mais longo para uma das cadeias de substituição dadas" (grifo nosso)Uma
perl
solução Mesmo que alguns tenham declarado que isso não é possível, eu encontrei um, mas geralmente não é possível uma correspondência simples e a substituição e até piora por causa do retorno de uma NFA, o resultado pode ser inesperado.Em geral, e isso deve ser dito, o problema gera diferentes resultados que dependem da ordem e do comprimento das tuplas de substituição. ou seja:
e a entrada
AAA
resulta emBBB
ouCCB
.Aqui o código:
Checkerbunny:
fonte