Я бы использовал Perl.Это больше однообразно, чем захватывающе.Вы создаете регулярное выражение, содержащее все альтернативные символы, а затем создаете более сложное регулярное выражение из этого и некоторых других битов и кусочков:
#!/usr/bin/env perl
use strict;
use warnings;
my $symbols = "Ac|Ag|Al|Am|Ar|As|At|Au|B|Ba|Be|Bh|Bi|Bk|Br|C|Ca|Cd|Ce|Cf|Cl|Cm|Cn|Co|Cr|Cs|Cu|Db|Ds|Dy|Er|Es|Eu|F|Fe|Fm|Fr|Ga|Gd|Ge|H|He|Hf|Hg|Ho|Hs|I|In|Ir|K|Kr|La|Li|Lr|Lu|Md|Mg|Mn|Mo|Mt|N|Na|Nb|Nd|Ne|Ni|No|Np|O|Os|P|Pa|Pb|Pd|Pm|Po|Pr|Pt|Pu|Ra|Rb|Re|Rf|Rg|Rh|Rn|Ru|S|Sb|Sc|Se|Sg|Si|Sm|Sn|Sr|Ta|Tb|Tc|Te|Th|Ti|Tl|Tm|U|Uuh|Uuo|Uup|Uuq|Uus|Uut|V|W|Xe|Y|Yb|Zn|Zr";
#my $symbols = "Ac|Ag|Al|...|Y|Yb|Zn|Zr";
my $regex = qr{ ([/ ]) ( (?:$symbols) (?: \d (?:$symbols) )* \d? ) ([ /]) }x;
printf "$regex\n";
while (<>)
{
s/$regex/$1\\chemical{$2}$3/g; # Handles first and third (, ...) in H2O CO2 H2SO4
s/$regex/$1\\chemical{$2}$3/g; # Handles second (fourth, ...)
print $_;
}
Первый захват касается пробела или косой черты перед символом.Второй снимок ужасен, дважды используя огромную строку в $symbols
.(?:...)
предназначены только для группировки, а не для захвата.Шаблон ищет химический символ, за которым, возможно, следует ноль или более последовательностей цифры и другого символа, возможно, с завершающей цифрой.Обратите внимание, что это то, что вы указали, но пропустите соединения, такие как H 2 SO 4 , CO 2 , KMnO 4 искоро.Вы можете подобрать их с помощью простой адаптации:
my $regex = qr{ ([/ ]) ( (?:$symbols) (?: \d* (?:$symbols) )* \d* ) ([ /]) }x;
Я также предполагаю однозначные цифры во всех соединениях.Это работает для многих, но некоторые из более длинных углеводородов не будут такими хорошими: CH 4 , C 2 H 6 , C 3 H 8 , C 4 H 10 , ... Опять же, вы можете справиться с этим, заменив 0-or-1 ?
на0 или более *
.У вас все еще есть проблемы с запятыми после соединений в списках, соединений в начале строки, соединений в конце строки и т. Д. - ваша спецификация исключает их все.
Возможно, вам лучше заменить первую итретий снимок с \b
, чтобы отметить границу между «словами» и «не словами», где химический символ будет считаться словом.Это касается проблем с запятыми, началом и концом строки, но обнаруживает больше, чем вы указали.
my $regex = qr{ \b ( (?:$symbols) (?: \d* (?:$symbols) )* \d* ) \b }x;
printf "$regex\n";
while (<>)
{
s/$regex/\\chemical{$1}/g;
print $_;
}
Обратите внимание, что эта формулировка не нуждается в двойной замене;достаточно одного, так что он определенно чище.