Любой вопрос Regex, чтобы разделить сводку из txt-файла

Я пытаюсь извлечь некоторый контент из txt-файла (из преобразования PDF). Вы можете заметить пробел (или его отсутствие) после метки или перед номером_страницы, а иногда между номером_страницы и кодом X.Y.Z нет \n. Вот образец:

Summary
...
30. LOT 03 CLOS COUVERT.................... 29 
30.1. LOT 03-1 ETANCHEITE .................... 29 
30.1.1. Travaux divers.................... 29 
30.1.1.1. Boite à eau.................... 29 
30.1.1.2. Descentes d’eaux pluviales en façades .................30 
30.1.1.3. Lanterneau de désenfumage...............30 30.1.1.4. Etanchéité résine..................31 
...

Структура резюме такова:

X.Y.Z. Label ....................... Page_number

И позже в том же документе мы можем найти связанное описание:

30. LOT 03 CLOS COUVERT (no description here)
30.1. LOT 03-1 ETANCHEITE (no description here)
...
30.1.1.1. Boite à eau 
Composition : -Descente d\’eaux pluviales 
o en zinc naturel, épaisseur 0.80 mm 
o en tle laquée jaune sur les zones d\’enduit jaune -Moignon cylindrique du diamètre de la descente EP -Trop-plein rectangulaire positionné sur face avant etc ...
30.1.1.2. Descentes d\’eaux pluviales en façades 
Fourniture et pose de descentes d\'eaux en zinc extérieures type VM Zinc
...

Мой вариант использования — поместить метку XYZ в словарь Python в качестве ключей только из сводки и связать с ней описания. Ожидаемый результат выглядит так:

{ '30. LOT 03 CLOS COUVERT' : '',
'30.1. LOT 03-1 ETANCHEITE' : '',
...
'30.1.1.1. Boite à eau' : 'Composition : -Descente d’eaux pluviales 
o en zinc naturel, épaisseur 0.80 mm 
o en tle laquée jaune sur les zones d\’enduit jaune -Moignon cylindrique du diamètre de la descente EP -Trop-plein rectangulaire positionné sur face avant etc ...',
'30.1.1.2. Descentes d\’eaux pluviales en façades' : 'Fourniture et pose de descentes d\'eaux en zinc extérieures type VM Zinc...'}

Я попробовал это регулярное выражение, и это лучший результат, который я могу получить, но это не лучший результат:

(\d+[.])(.*)?[.]*\s*\d+

Моя проблема связана с управлением точками, извлечением меток и отсутствием \n.

Не могли бы вы меня вылечить?

Я попытался исправить форматирование ввода. Но неясно, что на самом деле является частью файла: строка > Summary есть в файле или нет? И действительно ли оно включает в себя символ >. Пожалуйста, исправьте редактирование, если я ошибся.

Barmar 23.05.2024 17:52

После ? ставить (.*) нет смысла. * уже допускает совпадение нулевой длины, поэтому оно по своей сути необязательно.

Barmar 23.05.2024 17:54

Вы продолжаете говорить, что код X.Y.Z. Но примерные данные выглядят как W.X.Y.Z. Предполагается ли использовать в качестве ключа только первые три цифры?

Barmar 23.05.2024 17:58

Ни в одной из ваших образцовых линий нет Label :

Barmar 23.05.2024 17:58

Можете ли вы добавить к вопросу ожидаемый результат?

Barmar 23.05.2024 17:58

вы можете восполнить недостающие \n, сопоставив (^|\s) перед цифрами ключей.

Barmar 23.05.2024 18:00

Хорошо, запрос отредактирован, спасибо за отзыв! Я проверю все ваши предложения и отвечу правильным ;)

A.Dumas 24.05.2024 09:42
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
7
87
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

IIUC, вы можете использовать re.findall и (\d+(?:\.\d+)*\.) (.*?)\.* ?(\d+):

import re

txt = '''Summary
30.1.3.1. Boite à eau................................................................................................................................................. 29 
30.1.3.2. Descentes d’eaux pluviales en façades ....................................................................................................30 
30.1.3.3. Lanterneau de désenfumage.....................................................................................................................30 30.1.3.4. Etanchéité résine.......................................................................................................................................31 '''

out = re.findall(r'(\d+(?:\.\d+)*\.) (.*?)\.* ?(\d+)', txt)

out2 = {k: t for k, *t in out}

Выход:

# out
[('30.1.3.1.', 'Boite à eau', '29'),
 ('30.1.3.2.', 'Descentes d’eaux pluviales en façades ', '30'),
 ('30.1.3.3.', 'Lanterneau de désenfumage', '30'),
 ('30.1.3.4.', 'Etanchéité résine', '31')]

# out2
{'30.1.3.1.': ['Boite à eau', '29'],
 '30.1.3.2.': ['Descentes d’eaux pluviales en façades ', '30'],
 '30.1.3.3.': ['Lanterneau de désenfumage', '30'],
 '30.1.3.4.': ['Etanchéité résine', '31']}

демо регулярного выражения

Если вы просто хотите, чтобы метки были ключами, а описания — значениями:

out = dict(re.findall(r'(\d+(?:\.\d+)*\.) (.*?)\.* ?\d+', txt))

Выход:

{'30.1.3.1.': 'Boite à eau',
 '30.1.3.2.': 'Descentes d’eaux pluviales en façades ',
 '30.1.3.3.': 'Lanterneau de désenfumage',
 '30.1.3.4.': 'Etanchéité résine'}

спасибо за вашу помощь, но ваше регулярное выражение ведет себя странно (но оно лучше моего;)). Иногда этикетка обрезается, иногда добавляется часть описания (см. мое обновление), но не правильный код X.Y.Z : {'10.': 'Le choix des coloris se portera sur... '... }. Здесь «метка» неверна, поскольку значение dict является частью 40.5.2.2. описание. На этикетке должно быть «10. ЛОТ 01 VRD».

A.Dumas 24.05.2024 10:11

@A.Dumas ну, всегда сложно иметь полностью общее регулярное выражение, не зная всех угловых случаев. Рад, что вы нашли то, что вам помогло

mozway 24.05.2024 14:32
Ответ принят как подходящий

Вы можете использовать две группы захвата, где первая группа — это ключ, а вторая группа — описание.

Если речь идет конкретно о точках, которые вы хотите опустить:

\b(\d+(?:\.\d+)*)\.[^\S\n]+([\s\S]*?)\.{2,}\s*\d+\b

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

Пример

import pprint
import re
 
regex = r"\b(\d+(?:\.\d+)*)\.[^\S\n]+([\s\S]*?)\.{2,}\s*\d+\b"
 
s = ("> Summary\n"
            "30.1.3.1. Boite à eau................................................................................................................................................. 29 \n"
            "30.1.3.2. Descentes d’eaux pluviales en façades ....................................................................................................30 \n"
            "30.1.3.3. Lanterneau de désenfumage.....................................................................................................................30 30.1.3.4. Etanchéité résine.......................................................................................................................................31")
 
pprint.pprint(dict(re.findall(regex, s)))

Выход

{'30.1.3.1': 'Boite à eau',
 '30.1.3.2': 'Descentes d’eaux pluviales en façades ',
 '30.1.3.3': 'Lanterneau de désenfumage',
 '30.1.3.4': 'Etanchéité résine'}

Если вы хотите, чтобы вся часть включала точки прямо перед номером страницы, тогда значение группы 2 будет соответствовать до тех пор, пока либо новый ключ не начнется после номера страницы, ИЛИ пока это не будет последнее описание с номером страницы, за которым следует конец строки.

\b(\d+(?:\.\d+)*)\.[^\S\n]+([\s\S]*?)\s*\b(?=\d+\s*$|\d+\s+\d+(?:\.\d+)*\.)

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

Большое спасибо ! ваше регулярное выражение отлично справляется со своей задачей. Я обновил свой вопрос, добавив несколько запросов;) (об описании). Если у вас есть идея, было бы приятно.

A.Dumas 24.05.2024 10:05

Здравствуйте, у меня та же проблема с этим шаблоном: «12.2.1.1.1.1 Порт à 1 Vantail 7 12.2.1.1.2 Блоки распределения 5 тест 7 «Я не могу адаптировать регулярное выражение «\b(\ d+(?:\.\d+)*)\.[^\S\n]+([\s\S]*?)\.{2,}\s*\d+\b" без точки между меткой и номер страницы. У вас есть идея? Спасибо

A.Dumas 30.05.2024 14:40

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