Как найти персонажа после определенной строки?[Код химии] - PullRequest
1 голос
/ 06 июня 2019

Я пытаюсь написать код, в который я ввожу молекулу (для удобства использую только те, которые включают C, H, O, Cl и N) и получаю молекулярный вес.

Как если бы я ввел C2H4, он должен сделать расчет:

MW = mass_C * 2 + mass_H *4

Мне нужен код, чтобы взять букву (буквы) перед числом, а затем умножить его на число, следующее за «строкой», пока он не достигнет конца.

Так в принципе, как мне получить буквы перед числом?

PS: я новичок в кодировании :), поэтому было бы неплохо увидеть написанный код, а не просто объяснение, чтобы понять формат, который я должен использовать для RE.

Ответы [ 2 ]

2 голосов
/ 06 июня 2019

Вот простой код, который делает то, что вам нужно:

import re                                                                      

atomic_weights = {                                                             
    'Cl': 35.446,                                                              
    'C': 12.0096,                                                              
    'O': 15.99903,                                                             
    'H': 1.00784,                                                              
}                                                                              

pattern = r"(?P<element>" + "|".join(atomic_weights.keys()) + ")(?P<count>\d*)" 
expression = re.compile(pattern)                                               

while True:                                                                    
    formula = input("formula: ")                                               
    weight = 0                                                                 
    for match in expression.finditer(formula):                                 
        element = match.group('element')                                          
        count = match.group('count')                                           
        if count.isdigit():                                                    
            count = int(count)                                                 
        else:                                                                  
            count = 1
        weight += atomic_weights[element] * count                          
    print(f"{formula} weighs {weight}")

Я сосредоточусь только на использовании регулярных выражений:

  • сначала мы компилируем шаблон, используя следующие специальные символы:
    • | соответствует всему до или после него
    • \d соответствует всему, что является цифрой
  • и следующий классификатор:
    • *, который соответствует нулю или более (нам не обязательно нужно число)
  • и именованные группы:
    • (?P<name>) называет все, что соответствует, так что к нему можно будет снова обратиться позже

Затем мы сопоставляем формулу с созданным нами регулярным выражением и перебираем все совпадения, чтобы найти соответствующий вес элемента и множитель.

Небольшое примечание: этот метод будет полностью игнорировать элементы, вес которых он не знает. Это, вероятно, не то, что вы хотите ...

Надеюсь, это поможет!

0 голосов
/ 06 июня 2019

Я не уверен, что у меня есть атомные веса правильно, но я думаю, это можно исправить.

Для меня было непросто попытаться выяснить случаи, подобные CH3, где регулярное выражение (буквы) (цифры) не работает.

re.findall делает тяжелую работу здесь. Может быть лучший способ разобрать строку C2H4, и мне было бы интересно, но это работает. Очевидно, вы можете убирать вещи и делать аккуратные функции и т. Д.

Но регулярное выражение, которое, я подозреваю, вас больше всего интересует, говорит: ищите строку букв, в верхнем или нижнем регистре, а затем строку чисел. Это передается в calc_weight, который разделяет строку на буквы и цифры. Письма отправляются с атомным весом, если таковые имеются. Если нет, выдается ошибка. Затем вес умножается на число.

import re
import sys

weight = { 'cl': 30, 'n': 8, 'o': 12, 'c': 6, 'h': 2 }

def calc_weight(my_str):
    elt = my_str[1].lower()
    if not re.search("[0-9]", my_str[0]): amt = 1
    else: amt = re.sub("^[a-zA-Z]+", "", my_str[0])
    if elt not in weight: sys.exit(elt + " is not a valid element.")
    return int(amt) * weight[elt]

my_string = "C2H4"

a = re.findall("((Cl|H|O|C|N)[0-9]*)", my_string)

my_weight = 0
for b in a:
    my_weight += calc_weight(b)

print("Weight of", my_string, "is", my_weight)

Слово в коде: my_str [0] и my_str [1] являются частью кортежа из findall, потому что у меня есть две пары скобок. Первая - это общая строка, а вторая - элемент.

Надеюсь, это поможет. Обратите внимание, что вы, вероятно, можете улучшить код: выведите лучшее сообщение об ошибке для неверной строки и т. Д. Но я хотел бы, по крайней мере, разрешить использование заглавных букв, например. если кто-то напечатал Mg или MG, это не должно иметь никакого значения.

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