sed / awk números subscritos em fórmulas químicas usando tags de marcação

7

Eu tenho centenas de arquivos de texto que incluem fórmulas químicas juntamente com a narrativa, incluindo valores numéricos. As fórmulas são sempre precedidas por espaços em branco, mas podem ser seguidas por espaços em branco, vírgulas, pontos, etc.

O problema é: as fórmulas não são formatadas para exibir números como subscritos, por exemplo:

H2SO4, C5H11OH.

Eu quero formatar os subscritos como tags HTML, por exemplo:

H<sub>2</sub>SO<sub>4</sub>, C<sub>5</sub>H<sub>11</sub>OH

Para que os subscritos sejam renderizados em HTML, por exemplo:

H2SO4, C5H11OH

Eu brinquei com isso com Java, php, etc., mas as implementações são necessariamente confusas e desajeitadas. Eu suspeito que há uma abordagem elegante sed / awk.

Claramente, parte da solução é criar uma expressão regular que corresponda a uma letra seguida por um ou mais dígitos como mecanismo de detecção de fórmulas (pode haver falsos positivos que serão corrigidos manualmente mais tarde). Em seguida, dada uma fórmula identificada, uma substituição de sed precisa preceder cada dígito ou sequência de dígitos com a tag sub e segui-la com um encerramento de sub-tag.

Deve haver um one-liner que faça isso, mas eu estou acima da minha cabeça.

Alguma idéia?

    
por markb 21.04.2016 / 22:43

3 respostas

4

Por exemplo:

sed -r 's:([A-Za-z])([0-9]+):<sub></sub>:g'  

deve fazer o trabalho.

(Combine uma letra seguida por um grupo de dígitos e lembre-a como \ 1 e \ 2. Substitua tudo isso pela mesma letra (\ 1) mais o grupo de dígitos (\ 2) entre a tag sub .)

    
por 21.04.2016 / 22:52
3

Como você mencionou que pode haver falsos positivos para corrigir manualmente mais tarde, convém considerar um formulário um pouco mais robusto, que incorpore as seguintes restrições:

  1. Todos os símbolos químicos iniciam com uma letra maiúscula.
  2. Todos os símbolos químicos são uma única letra maiúscula ou uma única letra maiúscula seguida por uma única letra minúscula, exceto apenas designadores temporários que vou ignorar.

Considerando isso, você pode tentar, por exemplo:

sed 's|\([[:upper:]][[:lower:]]\{0,1\}\)\([0-9]\{1,\}\)|<sub></sub>|g'

Com a opção não-POSIX -r , isso se torna um pouco mais legível, mas menos portável:

sed -r 's|([[:upper:]][[:lower:]]?)([0-9]+)|<sub></sub>|g'

Isso poderia ser melhorado ainda mais, assegurando que a " toda " palavra "sendo trabalhada não contenha letras minúsculas consecutivas e, claro, poderia ser melhorada ainda mais verificando especificamente cada possível símbolo químico, mas isso fica mais chique e extravagante por menos recompensa. O acima deve reduzir drasticamente os falsos positivos já.

    
por 22.04.2016 / 02:52
2

Agrupamento e referências anteriores eram o truque. Obrigado pelo empurrão na direção certa. No final, usei o seguinte:

sed 's/\([A-Z][a-z]*\)\([0-9][0-9]*\)/<sub><\/sub>/g' file

Isto tolera os casos em que um cabeçalho, e. h2, ocorre no documento.

    
por 22.04.2016 / 15:46