У меня есть строка информации об учетной записи с несколькими учетными записями в строке (в примере показана одна строка, где на самом деле у меня есть текстовый файл с несколькими строками данных учетной записи, поэтому в моем коде есть еще один цикл, проходящий через каждую строку в текстовом файле. ). Мне нужно вытащить каждый аккаунт в свою строку. Приведенный ниже код работает, но я предполагаю, что есть более эффективный или лучший способ сделать это. Я только начинаю изучать Regex.
import re
import pandas as pd
allAccounts = []
example = '02-0015800-00 NAME1 100 SOME ST Active 3/8/2021 139.23 139.81 0.42 02-0023901-01 NAME2 101 SOME ST Active 3/8/2021 512.33 482.96 -5.73'
rex = '[0-9]{1,2}-[0-9]{1,7}-[0-9]{1,2}'
accounts = re.findall(rex, example)
for account in accounts:
example= example.replace(account, f'||{account}')
example = [account.replace(' ', '|').split('|') for account in example.split('||')][1:]
allAccounts += example
df = pd.DataFrame(allAccounts)
df
из части регулярного выражения кода я хочу, чтобы он возвращался:
['02-0015800-00 NAME1 100 SOME ST Active 3/8/2021 139.23 139.81 0.42', ' 02-0023901-01 NAME2 101 SOME ST Active 3/8/2021 512.33 482.96 -5.73']
# or
'||02-0015800-00 NAME1 100 SOME ST Active 3/8/2021 139.23 139.81 0.42 ||02-0023901-01 NAME2 101 SOME ST Active 3/8/2021 512.33 482.96 -5.73'
Код возвращает следующий df, что в конечном итоге я и хочу:
0 1 2 3 4 5 6 7 8
0 02-0015800-00 NAME1 100 SOME ST Active 3/8/2021 139.23 139.81 0.42
1 02-0023901-01 NAME2 101 SOME ST Active 3/8/2021 512.33 482.96 -5.73 None
Но я чувствую, что есть лучший способ использовать регулярное выражение, чем то, что я делаю. Читая документы, кажется, что re.sub должен это сделать, но он заменяет только первый номер учетной записи, который встречается, и хочет только заменить номер учетной записи, а не добавлять «||» разделитель в начало.
Обновить:
Используя следующее, он приближается к тому, что я хочу, но не уверен, почему первым элементом в списке является ''.
example = '02-0015800-00 NAME1 100 SOME ST Active 3/8/2021 139.23 139.81 0.42 02-0023901-01 NAME2 101 SOME ST Active 3/8/2021 512.33 482.96 -5.73'
rex = re.compile('(?=[0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9])')
re.split(rex, example)
выходы:
['',
'02-0015800-00 NAME1 100 SOME ST Active 3/8/2021 139.23 139.81 0.42 ',
'02-0023901-01 NAME2 101 SOME ST Active 3/8/2021 512.33 482.96 -5.73']
Я не могу заставить re.split работать. я хочу, чтобы регулярное выражение возвращало ['02-0015800-00 NAME1 100 SOME ST Active 3/8/2021 139.23 139.81 0.42', ' 02-0023901-01 NAME2 101 SOME ST Active 3/8/2021 512.33 482.96 -5.73'] или '||02-0015800-00 NAME1 100 SOME ST Active 3/8/2021 139.23 139.81 0.42 ||02-0023901-01 NAME2 101 SOME ST Active 3/8/2021 512.33 482.96 -5.73'. Где в последнем я могу использовать '||' разделить каждую учетную запись на список.
Другой подход: в каждой строке задано количество полей (кажется, их восемь), верно? Что, если вы просто разделите данные на поля (разделенные двойным пробелом), а затем преобразуете эти данные в 8 х N?
@Karl Knechtel Хотел бы я, чтобы это было так просто, но их не все 8, у некоторых 7, а у некоторых 9
Откуда взялись эти данные? В случаях, когда имеется 9 значений, что они все представляют? В случаях, когда их менее 9, всегда ли отсутствуют одни и те же? Поскольку подобные неоднородные данные — гораздо более серьезная проблема, о которой следовало упомянуть заранее — смысл DataFrame в том, что они представляют собой прямоугольную, непротиворечивую таблицу данных.
@Карл Кнехтель, нет, ты слишком много читаешь. Как только я разделю данные на списки, я буду использовать только первые 5 элементов в списке для создания фрейма данных, так что это не является частью вопроса, а просто показывает окончательные конечные результаты. Я спрашиваю только о регулярном выражении кода.
@Karl Knechtel Я немного отредактировал вопрос, чтобы, надеюсь, прояснить ситуацию.






Вместо использования разделения вы можете сопоставить значения:
\b\d\d-\d{7}-\d\d\b.*?(?=\s*\b\d\d-\d{7}-\d\d\b.*?|$)
Объяснение
\b\d\d-\d{7}-\d\d\b Сопоставьте шаблон с 2 цифрами - 7 цифрами - 2 цифрами, используя квантификатор.*? Подберите любой символ как можно меньше(?=\s*\b\d\d-\d{7}-\d\d\b.*?|$) Положительный просмотр вперед, чтобы подтвердить либо шаблон цифр справа, либо конец строки, чтобы также соответствовать последнему вхождениюДемонстрация регулярных выражений
Пример
import re
pattern = r"\b\d\d-\d{7}-\d\d\b.*?(?=\s*\b\d\d-\d{7}-\d\d\b.*?|$)"
s = "02-0015800-00 NAME1 100 SOME ST Active 3/8/2021 139.23 139.81 0.42 02-0023901-01 NAME2 101 SOME ST Active 3/8/2021 512.33 482.96 -5.73"
print(re.findall(pattern, s))
Выход
['02-0015800-00 NAME1 100 SOME ST Active 3/8/2021 139.23 139.81 0.42', '02-0023901-01 NAME2 101 SOME ST Active 3/8/2021 512.33 482.96 -5.73']
Если вы должны использовать разделение:
импортировать повторно
pattern = r"\b(?=\d\d-\d{7}-\d\d\b)"
s = "02-0015800-00 NAME1 100 SOME ST Active 3/8/2021 139.23 139.81 0.42 02-0023901-01 NAME2 101 SOME ST Active 3/8/2021 512.33 482.96 -5.73"
result = [m.strip() for m in re.split(pattern, s) if m]
print(result)
четвертая птица Мне нравится разделенная версия вашего ответа, по крайней мере, для меня легче увидеть, что делает код. Спасибо за объяснение, это очень помогает. Какова цель \b в начале и в конце шаблона? Одна версия быстрее другой?
Вам действительно нужно регулярное выражение, которое соответствует всей информации об учетной записи, или вам просто нужно уметь находить границы? Если второе, то какое фактическое правило говорит вам, где заканчивается информация одной учетной записи и начинается следующая? Просматривая документацию модуля
re, вы виделиre.split? 90% программирования — это точно понимания проблемы, которую необходимо решить.