Regex - различение очень похожих подстрок с использованием самой подстроки

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

Я пытаюсь разобрать текст из книги по химии и преобразовать его в JSON, но у меня возникают проблемы с разделением текста по его основному идентификатору. Все это делается в среде Python 3.10.

Рассмотрим следующую строку:

0047 Heptasilver nitrate octaoxide
[12258-22-9] Ag NO
7 11
(Ag O ) .AgNO
3 4 2 3
Alone, or Sulfides, or Nonmetals
The crystalline product produced by electrolytic oxidation
of silver nitrate (and possibly as formulated) detonates
feebly at 110°C. Mixtures with phosphorus and sulfur
explode on impact, hydrogen sulfide ignites on contact,
and antimony trisulfide ignites when ground with the salt.
Mellor, 1941, Vol. 3, 483–485
See other SILVER COMPOUNDS
See related METAL NITRATES
0048 Aluminium
[7429-90-5] Al
Al
HCS 1980, 135 (powder)
Finely divided aluminium powder or dust forms highly
explosive dispersions in air [1], and all aspects of pre-
vention of aluminium dust explosions are covered in 2
US National Fire Codes [2]. The effects on the ignition
properties of impurities introduced by recycled metal used
to prepare dust were studied [3]. Pyrophoricity is elimi-
nated by surface coating aluminium powder with poly-
styrene [4]. Explosion hazards involved in arc and flame
spraying of the powder were analyzed and discussed [5],
and the effect of surface oxide layers on flammability
was studied [6]. The causes of a severe explosion in
1983 in a plant producing fine aluminium powder were
analyzed, and improvements in safety practices discussed
[7]. A number of fires and explosions involving aluminiumdust arising from grinding, polishing, and buffing opera-
tions were discussed, and precautions detailed [8] [12]
[13]. Atomized and flake aluminium powders attain
See other METALS
See other REDUCANTS
0049 Aluminium-cobalt alloy (Raney cobalt alloy)
[37271-59-3] 50:50; [12043-56-0] Al Co; Al—Co
5
[73730-53-7] Al Co
2
Al Co
The finely powdered Raney cobalt alloy is a significant
dust explosion hazard.
See DUST EXPLOSION INCIDENTS (reference 22)
0050 Aluminium–copper–zinc alloy
(Devarda’s alloy)
[8049-11-4] Al—Cu—Zn
Al Cu Zn
Silver nitrate: Ammonia, etc.
See DEVARDA’S ALLOY
See other ALLOYS0051 Aluminium amalgam (Aluminium–
mercury alloy)
[12003-69-9] (1:1) Al—Hg
Al Hg
The amalgamated aluminium wool remaining from prepa-
ration of triphenylaluminium will rapidly oxidize and
become hot upon exposure to air. Careful disposal is nec-
essary [1]. Amalgamated aluminium foil may be pyro-
phoric and should be kept moist and used immediately [2].
1. Neely, T. A. et al., Org. Synth., 1965, 45, 109
2. Calder, A. et al., Org. Synth., 1975, 52, 78
See other ALLOYS

Эта строка содержит информацию о 5 различных соединениях, которые идентифицируются 4-значным номером в начале, за которым следует название, а затем в другой строке уникальный идентификатор CAS в квадратных скобках.

Я пытаюсь разделить это на отдельные подстроки для каждого объекта, идентифицируя 4-значное число, за которым всегда следуют другие идентификаторы, и разделяя текст в этой точке.

В настоящее время я использую это регулярное выражение, которое правильно определяет 4-значные идентификаторы:

\n(\d{4})\s(?:[\s\S]*?)(?:\[\d*?-\d*?-\d*?\]|\[ *?\] [a-zA-Z]*?)

Однако это также включает в себя несколько экземпляров других 4-значных чисел, которые не являются идентификаторами, например даты в основном тексте, такие как дата «1983» в тексте составной записи алюминия (0048).

Я пытался использовать отрицательный просмотр вперед с тем же выражением, которое я использую для выделения 4-значного идентификатора, но ни один из способов, которые я пробовал, не работал. И теперь я не уверен, возможно ли это вообще, или, возможно, я слишком усложняю это.

Другой способ сделать это — использовать CAS (в квадратных скобках), но это будет хуже, так как есть записи с несколькими или даже пустыми CAS.

Любой совет будет принят с благодарностью!

Каково правило, чтобы 4 цифры не были годом? Должна ли строка с 4 цифрами всегда сопровождаться строкой, начинающейся с [ или (? Или 4 цифры всегда должны начинаться с нуля? Или ему должен предшествовать See в строке перед?

The fourth bird 04.05.2022 16:16

Возможно вот так ^See.*\n(\d{4})\s(?:[\s\S]*?)(?:\[\d+-\d+-\d+])regex101.com/r/MHk5qr/1 или вот так \n(\d{4}).*(?:\n\(.*)*\n\[\d+-\d+-\d+]regex101.com/r/czf39b/1

The fourth bird 04.05.2022 16:24

@Thefourthbird Правило состоит в том, что за ним сразу следует имя (текст с буквами, цифрами и символами), разрыв строки и последовательность чисел, заключенных в квадратные скобки.

Ricardo Bessa 04.05.2022 16:30

Звучит как ^(\d{4}).*\n\[\d+-\d+-\d+]regex101.com/r/64EMh7/1

The fourth bird 04.05.2022 16:33

@Thefourthbird Последнее выражение, кажется, отлично работает для разделения дат и намного проще, чем то, что я экспериментировал до сих пор. Единственное, чего ему не хватает, так это учета пустых квадратных скобок, но это достаточно легко исправить. Большое спасибо!

Ricardo Bessa 04.05.2022 16:33
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
5
31
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Несколько замечаний по вашему шаблону:

  • Вы можете опустить [a-zA-Z]*? в конце шаблона, так как это последняя часть и не жадная, поэтому она не будет соответствовать никаким символам.
  • такие части, как \d*?-\d*?-\d*? и \[ *?\], не должны быть не жадными, поскольку указанный повторяемый символ не может пересекать следующий символ

Если совпадение всегда должно начинаться с новой строки:

\n(\d{4}).*(?:\n\(.*)*\n\[(?: *|\d+-\d+-\d+)]

Объяснение

  • \n Совпадение с новой строкой
  • (\d{4}) Запишите 4 цифры в группа 1
  • .* Сопоставьте остальную часть строки
  • (?:\n\(.*)* При желании повторите сопоставление новой строки и (, за которой следует остальная часть строки
  • \n Совпадение с новой строкой
  • \[(?: *|\d+-\d+-\d+)] Совпадение [...], где могут быть только пробелы или цифры с дефисом между ними

См. демонстрация регулярных выражений.

Если квадратные скобки должны быть прямо на следующей строке:

^(\d{4}).*\n\[(?: *|\d+-\d+-\d+)]

См. другой демонстрация регулярных выражений.

Еще раз большое спасибо. Но еще один вопрос, если не возражаете. Что делать, если текст, следующий за 4-значным идентификатором, занимает несколько строк?

Ricardo Bessa 04.05.2022 17:21

@RicardoBessa Можете ли вы создать здесь пример регулярного выражения101 с частью, которую вы хотите сопоставить, и поделиться ссылкой здесь?

The fourth bird 04.05.2022 17:24

Я нашел хороший пример проблемы, здесь regex101.com/r/RfgDCO/1

Ricardo Bessa 04.05.2022 17:34

@RicardoBessa И вы хотите сопоставить все строки после этого? До следующего появления 4 цифр или конца строки? Примерно так regex101.com/r/aHnjTm/1

The fourth bird 04.05.2022 17:34

@RicardoBessa Или как regex101.com/r/9jbl8h/1

The fourth bird 04.05.2022 17:39

Нет, в этом случае я хочу только сопоставить текст между 4-значным идентификатором и первыми квадратными скобками. Пример, который я разместил с идентификаторами 0071 и 0072, показывает мою проблему, когда я пытаюсь сопоставить многострочные имена, он также может поймать нежелательный текст, если есть дата

Ricardo Bessa 04.05.2022 18:03

@RicardoBessa попробуй regex101.com/r/cwq98i/1

The fourth bird 04.05.2022 18:16

О да, кажется, это прекрасно работает. Это довольно сложно, поэтому мне потребуется немного времени, чтобы полностью понять логику, стоящую за ним. Большое спасибо, что показали мне, как это сделать!

Ricardo Bessa 04.05.2022 18:24

Другие вопросы по теме