Использование регулярного выражения для извлечения числа - PullRequest
3 голосов
/ 07 октября 2019

Как извлечь числовое выражение из string, которое может иметь или не иметь underscore или hyphen. Например,как 2016-03 или 2016_03 или просто 201603.

Примеры строк:

s = 'Total revenue for 2016-03 is 3000 €'  # Output 2016-03
s = 'Total revenue for 2016_03 is 3000 €'  # Output 2016_03
s = 'Total revenue for 201603 is 3000 €'   # Output 201603

Есть 6 чисел, и в случае, если у нас есть либо -, либо _, тогда общая длина равна 7. Во всей строке нет никакого number.

Я не знаю, как использовать if-else в regex, так что в него может входить логикадлина 6 или 7. Для простых строк, таких как 201603, я могу это сделать -

import re
print(re.findall('\d{6}','Total revenue for 201603 is 3000 €'))
['201603']

print(re.findall('\d{6}','Total revenue for 2016-03 is 3000 €'))
[]

Примечание: Я ищу решение, где теоретически _ или - может быть где угодно между 6-ю номерами длины. Как 123-456 или 123456 или 12345-6 и т. Д.

Ответы [ 4 ]

2 голосов
/ 07 октября 2019

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

См. * 1003. * Python demo :

import re
s = 'Total revenue for 201603 is 3000 €'
rx = re.compile(r'^(?=\d+(?:[_-]\d+)?$)[\d_-]{6,7}$')
res = [x for x in s.split() if rx.search(x)]
if len(res):
    print(res[0])

# Pure regex approach:
rx = re.compile(r'(?<!\S)(?=\d+(?:[_-]\d+)?(?!\S))[\d_-]{6,7}(?!\S)')
res = rx.search(s)
if res:
    print(res.group())

Итак, при первом подходе строка разделяется пробелами, и шаблон ^(?=\d+(?:[_-]\d+)?$)[\d_-]{6,7}$ применяется к каждому элементу, и, если есть совпадения,первый возвращается. Шаблон соответствует:

  • ^ - начало строки
  • (?=\d+(?:[_-]\d+)?$) - положительный прогноз, который гарантирует, что есть 1+ цифр, затем _ или -и затем снова 1+ цифр до конца строки,
  • [\d_-]{6,7} - соответствует 6 или 7 цифрам, - или _
  • $ - конец строки.

Второй подход включает только регулярное выражение, и якорь ^ заменяется на (?<!\S), а $ заменяется на (?!\S), которые действуют как границы пробелов. (?<!\S) - это отрицательный взгляд назад, для которого требуется пробел или начало строки непосредственно перед текущей позицией, а (?!\S) - это отрицательный взгляд, который требует пробела или конца строки сразу после текущей позиции.

1 голос
/ 07 октября 2019

Вы можете использовать положительный вид сзади, если уверены, что требуемое значение всегда соответствует стандартному шаблону

(?<=^Total revenue for )\d+[-_]?\d+
  • (?<=^Total revenue for ) - совпадению должно предшествовать Total revenue for, ^начало с начала строки
  • \d+ - соответствует одной или нескольким цифрам
  • [-_]? - соответствует - or _ (необязательно)

Regex Demo


Или вы можете расширить вышеприведенное регулярное выражение таким образом, если вы не уверены, что требуемый формат значения

(?<=^Total revenue for )(?=\d+[-_]?\d+)[\d_-]{6,7}(?!\S)
  • (?=\d+[-_]?\d+)- Для обеспечения digit followed by - or _ optional followed by digit
  • [\d_-]{6,7} - Для совпадения digit or - or _, 6 or 7 times
  • (?!\S) - Не должно сопровождаться пробелом

Regex Demo

0 голосов
/ 07 октября 2019

Ваш RegEx следующий: начинается с пробела, последовательность не менее одной цифры (цифр) и заканчивается пробелом. Это приходит к следующему:

\s(\d*)\s

Проверьте это здесь: https://regex101.com/r/V4NzLj/1

0 голосов
/ 07 октября 2019

Это должно сделать это довольно просто:

print(re.findall(r'\d{4}[-_]?\d{2}', 'Total revenue for 201603 is 3000 €'))
# ['201603']

В частности, это «Четыре цифры, за которыми следует либо ноль, либо одно вхождение либо '-', либо '_', а затем еще две цифры»,Если дефис или знак подчеркивания отсутствуют, четырехзначные и двухзначные цифры заканчиваются тем же, что и запрос шестизначного числа. однако, есть одна вещь, которую вы можете сделать, просто отфильтровав ее:

nums = re.findall(r'\d{4}[-_]?\d{2}', 'Total revenue for 2016-03 is 3000 €')
# nums = ['2016-03']
nums = [num.replace('-', '').replace('_', '') for num in nums]
# nums = ['201603']

Обратите внимание, что это решение, которое меньше всего мешает вашему исходному регулярному выражению, и будет искать этот шаблон из "четырехцифры, после которых может быть разделитель, а затем две цифры в любом месте строки. Если вы хотите ограничить это значение просто строкой, которую вы пытаетесь найти, игнорируя аналогичные строки, вам может понадобиться сделать регулярное выражение более конкретным. См. Также документацию re

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