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

У меня есть регулярное выражение, которое выглядит так, чтобы извлечь номера заказов из столбцов:

df["Orders"].str.extract('([0-9]{9,10}[/+ #_;.-]?)')

Колонка заказов может выглядеть так:

12
123456789
1234567890
123456789/1234567890
123456789/1/123456789
123456789+1234567890

Результирующий новый столбец в фрейме данных после регулярного выражения должен выглядеть так:

NaN
123456789
1234567890
123456789/1234567890
123456789/123456789
123456789+1234567890

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

NaN
123456789
1234567890
123456789/
123456789/
123456789+

Как я могу получить результат, который я ищу?

df["Orders"].str.findall(r'[/+ #_;.-]?\b[0-9]{9,10}\b').str.join('') помогает?

Wiktor Stribiżew 13.05.2022 23:08

@ j1-lee заказы, идущие после косой черты, знаков плюса, хэштегов и т. д., которые соответствуют 9 или 10 цифрам, на самом деле являются заказами. Затем они в конечном итоге будут взорваны, чтобы создать множество разных рядов.

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

Ответы 2

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

Ты можешь использовать

import pandas as pd
df = pd.DataFrame({'Orders':['12','123456789','1234567890','123456789/1234567890','123456789/1/123456789','123456789+1234567890', 'Order number: 6508955960_000010_1005500']})
df["Result"] = df["Orders"].str.findall(r'[/+ #_;.-]?(?<![0-9])[0-9]{9,10}(?![0-9])').str.join('').str.lstrip('/+ #_;.-')
df.loc[df['Result'] == '', 'Result'] = np.nan

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

  • [/+ #_;.-]?(?<![0-9])[0-9]{9,10}(?![0-9]) - соответствует необязательным символам /, +, пробелу, #, _, ;, . или -, а затем ни одному или десятизначному числу, не заключенному в другие цифры
  • Series.str.findall извлекает все вхождения
  • .str.join('') объединяет совпадения в одну строку
  • .str.lstrip('/+ #_;.-') - удаляет специальные символы, совпавшие с числом в начале строки
  • df.loc[df['Result'] == '', 'Result'] = np.nan - при необходимости - заменяет пустые строки значениями np.nan в столбце Result.

Выход:

>>> df
                  Orders                Result
0                    NaN                   NaN
1              123456789             123456789
2             1234567890            1234567890
3   123456789/1234567890  123456789/1234567890
4  123456789/1/123456789   123456789/123456789
5   123456789+1234567890  123456789+1234567890
>>> 

Хм, что-то вроде этого: Order number: 6508955960_000010_1005500 возвращает пробел... Это должно вернуть 6508955960

user2896120 13.05.2022 23:16

@user2896120 user2896120 Переключиться на числовые границы.

Wiktor Stribiżew 13.05.2022 23:18

Спасибо, это исправляет это, есть ли способ удалить ведущий #,+,etc., чтобы он удалил что-то вроде # 6508955960 в регулярном выражении? Или было бы проще сделать ltrim

user2896120 13.05.2022 23:25

@user2896120 user2896120 Регулярное выражение усложняет сопоставление с образцом. Я бы просто использовал lstrip

Wiktor Stribiżew 13.05.2022 23:34

Вы можете адаптировать следующий код для работы с фреймами данных,

Регулярное выражение: (?:^|([/+ #_;.-]))(?:\d{1,8})(?!\d)

  • (?:\d{1,8})(?!\d) - найти число (<9 цифр)
  • ([/+ #_;.-]) - перед ним стоит один или ни один из возможных разделителей (группа №1)

Условно замените на NaN или пустую строку — subst использует match.group(1), чтобы различать два варианта:

  • автономный-недействительный - 12
  • недействительный-с-разделителем - /1
import re

regex = r"(?:^|([/+ #_;.-]))(?:\d{1,8})(?!\d)"

test_str = ("12\n"
            "123456789\n"
            "1234567890\n"
            "123456789/1234567890\n"
            "123456789/1/123456789\n"
            "123456789+1234567890")

def subst(match):
    m = match.group(1)
    return "" if m else "NaN"

result = re.sub(regex, subst, test_str, 0, re.MULTILINE)

if result:
    print(result)

Выход:

NaN
123456789
1234567890
123456789/1234567890
123456789/123456789
123456789+1234567890

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