Поиск всех химических символов в файле - PullRequest
5 голосов
/ 11 марта 2012

У меня есть файл, содержащий множество химических формул. Мне нужно отметить любой текст, который является химической формулой. Я хочу найти файл для любого места, содержащего комбинацию хотя бы одного химического символа и хотя бы одного числа, и добавить \chemical{} вокруг него. Например. H2O становится \chemical{H2O}, а FeS2 становится \chemical{FeS2}.

  • Химические вещества ограничены пробелами () или косыми чертами (/". Например: /Ar становится /\chemical{Ar}, но Arizona не следует идентифицировать как `\ chemical {Ar} izona" .
  • Комбинации, не содержащие чисел, следует игнорировать.
  • Я нашел этот список, который, как мне кажется, имеет всевозможные химические названия: «Ас, 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, Нет , 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 ".

Как мне найти все химические формулы, появляющиеся в файле?

Ответы [ 2 ]

6 голосов
/ 11 марта 2012

Я бы использовал 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 $_;
}

Обратите внимание, что эта формулировка не нуждается в двойной замене;достаточно одного, так что он определенно чище.

2 голосов
/ 11 марта 2012

Использование awk:

awk 'BEGIN{
  strElements="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"
  n = split(strElements, arrElements)
  for(i = 0; i < n; i++)
    hashElements[arrElements[i]] = 1}
  {for(i = 1; i <= NF; i++) {
    str = substr($i, 1, 1) == "/" ? substr($i, 2) : $i
    n = split(str, elements, "[0123456789]+")
    while (n > 0) {if (!(elements[n] in hashElements)) break; n--}
    if (n == 0)
      $i = (substr($i, 1, 1) == "/" ? "/" : "") "\\chemical{" str "}"
    }
  print}' your_file

Идея сценария заключается в следующем:

  1. Создание хэша из всех элементов (в awk массивы являются ассоциативными).
  2. Для каждой строки, берите по одному слову за раз, разбейте его по номеру и посмотрите, является ли каждое подслово элементом.
  3. Если это так, окружите химическое веществотребуемая строка.

Конечно, необходимо добавить некоторую логику, чтобы учесть специальный символ /.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...