查找文件中的所有化学符号

Vil*_*age 5 bash sed

我有一个包含许多化学公式的文件.我需要标记任何化学式的文本.我想在文件中搜索包含至少一个化学符号和至少一个数字的组合的任何地方,并\chemical{}在其周围添加.例如,H2O变得\chemical{H2O}FeS2\chemical{FeS2}.

  • 化学物质以空间() or forward-slashes (/"例如:/Ar变为/\chemical{Ar},但Arizona不应被称为"\ chemical {Ar} izona".
  • 不应忽略不包含数字的组合.
  • 我发现这个列表我认为有各种可能的化学名称:"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" .

如何找到文件中出现的所有化学公式?

Jon*_*ler 6

我用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 $_;
}
Run Code Online (Sandbox Code Playgroud)

第一次捕获处理符号前的空格或斜线.第二次捕获是令人毛骨悚然的,使用$symbols两次的幽默弦.这(?:...)纯粹是为了分组而不是捕获.该模式寻找化学符号,可选地后跟零个或多个数字序列和另一个符号,可能带有尾随数字.请注意,这是您指定的,但会遗漏H 2 SO 4,CO 2,KMnO 4等化合物.你可以通过简单的改编来挑选它们:

my $regex = qr{ ([/ ]) ( (?:$symbols) (?: \d* (?:$symbols) )* \d* ) ([ /]) }x;
Run Code Online (Sandbox Code Playgroud)

我也假设所有化合物都有一位数.这适用于许多人,但一些较长的碳氢化合物将不会那么好: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 $_;
}
Run Code Online (Sandbox Code Playgroud)

注意,该配方不需要双重替代; 一个就足够了,所以它绝对更清洁.