sed / awk-Indexnummern in chemischen Formeln unter Verwendung von Markup-Tags

7

Ich habe Hunderte von Textdateien, die chemische Formeln zusammen mit Erzählungen einschließlich numerischer Werte enthalten. Vor den Formeln stehen immer Leerzeichen, gefolgt von Leerzeichen, Kommas, Punkten usw.

Das Problem ist: Die Formeln sind nicht so formatiert, dass Zahlen als Indizes angezeigt werden, z.

H 2 SO 4, C 5 H 11 OH.

Ich möchte die Indizes als HTML-Tags formatieren, z.

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

Damit Indizes in HTML gerendert werden, z.

H 2 SO 4 , C 5 H 11 OH

Ich habe damit gespielt, dies mit Java, PHP usw. zu erreichen, aber die Implementierungen sind notwendigerweise chaotisch und umständlich. Ich vermute, dass es einen eleganten Sed / Awk-Ansatz gibt.

Ein Teil der Lösung besteht eindeutig darin, einen regulären Ausdruck zu erstellen, der mit einem Buchstaben gefolgt von einer oder mehreren Ziffern als Formelerkennungsmechanismus übereinstimmt (es kann falsch positive Ergebnisse geben, die ich später manuell korrigieren werde). Bei einer so identifizierten Formel muss ein sed-Ersatz vor jeder Ziffer oder Ziffernfolge mit dem subTag versehen und anschließend mit einem Sub-Tag-Abschluss versehen werden.

Es muss einen Einzeiler geben, der das macht, aber ich bin über meinem Kopf.

Irgendwelche Ideen?

markb
quelle
Gibt es einen Grund, warum Sie ein Bild anstelle eines Inline-Codeblocks hinzugefügt haben? Weitere Formatierungshilfe: Hilfezentrum
Katze

Antworten:

4

Z.B:

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

sollte den Job machen.

(Ordnen Sie einen Buchstaben gefolgt von einer Gruppe von Ziffern zu und merken Sie sich diesen als \ 1 und \ 2. Ersetzen Sie all diesen durch denselben Buchstaben (\ 1) plus die im subTag enthaltene Zifferngruppe (\ 2) .)

PSkocik
quelle
3

Da Sie erwähnen, dass möglicherweise falsch positive Ergebnisse später manuell korrigiert werden müssen, sollten Sie eine etwas robustere Form in Betracht ziehen, die die folgenden Einschränkungen enthält:

  1. Alle chemischen Symbole beginnen mit einem Großbuchstaben.
  2. Alle chemischen Symbole sind entweder ein einzelner Großbuchstabe oder ein einzelner Großbuchstabe, gefolgt von einem einzelnen Kleinbuchstaben, mit Ausnahme nur temporärer Bezeichner, die ich ignorieren werde.

Mit diesen könnten Sie zum Beispiel versuchen:

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

Mit der Nicht-POSIX- -rOption wird dies etwas besser lesbar, aber weniger portabel:

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

Dies könnte noch weiter verbessert werden, indem sichergestellt wird, dass das gesamte "Wort", an dem gearbeitet wird, keine aufeinanderfolgenden Kleinbuchstaben enthält, und natürlich könnte es noch weiter verbessert werden, indem spezifisch nach jedem möglichen chemischen Symbol gesucht wird, aber das wird immer schicker für weniger Auszahlung. Das oben Genannte sollte bereits falsch positive Ergebnisse drastisch reduzieren.

Platzhalter
quelle
2
Wie pro unix.stackexchange.com/questions/267148/... können Sie verwenden -Estatt -rund „POSIX-y“ bleiben.
Dani_l
Es ist nicht weniger tragbar - es ist genauso tragbar wie das erste (dh nicht tragbar; für tragbares BRE siehe die Antwort von OP).
don_crissti
@don_crissti, welcher Teil meines ersten Befehls ist Nicht-POSIX?
Wildcard
1
\?und \+... gnu sedund andere Apps / Implementierungen sind "intelligent", sodass sie diese Qualifikationsmerkmale verstehen, auch wenn sie laut Standard nicht BRE sind.
don_crissti
@don_crissti, danke; Das habe ich nie bemerkt. Ich sehe, dass es in BSD nicht sedwie ursprünglich geschrieben funktioniert . Ich habe es jetzt behoben, um POSIX-spezifizierte Quantifizierer zu verwenden .
Wildcard
2

Gruppierung und Rückverweise waren der Trick. Danke für den Schub in die richtige Richtung. Am Ende habe ich folgendes verwendet:

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

Dies toleriert die Fälle, in denen ein Header, z. B. h2, im Dokument vorkommt.

markb
quelle