регулярное выражение, чтобы найти пару соседних цифр с разными цифрами вокруг них - PullRequest
57 голосов
/ 19 июня 2020

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

Например,

123456678 должно совпадать, поскольку есть двойное число 6,

1234566678 не должно совпадать, поскольку нет двойного с другими окружающими числами. 12334566 должен совпадать, потому что есть две тройки.

Пока что у меня есть это, которое работает только с 1, и пока двойное не находится в начале или конце строки, однако я могу справиться с этим, добавление буквы в начале и в конце.

^.*([^1]11[^1]).*$

Я знаю, что могу использовать [0-9] вместо единиц, но проблема в том, что все они будут одинаковыми di git.

Спасибо!

Ответы [ 4 ]

34 голосов
/ 19 июня 2020

Я разделил свой ответ на четыре части.

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

Остальные три раздела связаны с идентификацией пар одинаковых цифр, которым предшествует другой di git и за которым следует другой di git . Им соответствует первый из трех разделов; другие два захватывают их в группу.

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

Определите, содержит ли строка две последовательные одинаковые цифры, которым предшествует другой di git, за которым следует другой di git

Вы можете проверить строку следующим образом:

import re

r = r'(\d)(?!\1)(\d)\2(?!\2)\d'
arr = ["123456678", "1123455a666788"]
for s in arr:
  print(s, bool(re.search(r, s)) )

отображает

123456678 True
1123455a666788 False

Выполнить Python код | Запустите двигатель! 1

Механизм регулярных выражений выполняет следующие операции.

(\d)    : match a digit and save to capture group 1 (preceding digit)
(?!\1)  : next character cannot equal content of capture group 1
(\d)    : match a digit in capture group 2 (first digit of pair)
\2      : match content of capture group 2 (second digit of pair)
(?!\2)  : next character cannot equal content of capture group 2
\d      : match a digit

(?!\1) и (?!\2) равны отрицательный просмотр вперед .

Используйте модуль Python s regex для сопоставления пар последовательных цифр, которые имеют желаемое свойство

Вы можете использовать следующее регулярное выражение с модулем Python regex для получения совпадающих пар цифр.

r'(\d)(?!\1)\K(\d)\2(?=\d)(?!\2)'

Regex Engine

Механизм регулярных выражений выполняет следующие операций.

(\d)    : match a digit and save to capture group 1 (preceding digit)
(?!\1)  : next character cannot equal content of capture group 1
\K      : forget everything matched so far and reset start of match
(\d)    : match a digit in capture group 2 (first digit of pair)
\2      : match content of capture group 2 (second digit of pair)
(?=\d)  : next character must be a digit
(?!\2)  : next character cannot equal content of capture group 2

(?=\d) - это положительный просмотр вперед . (?=\d)(?!\2) можно заменить на (?!\2|$|\D).

Сохранить пары последовательных цифр, которые имеют желаемое свойство, в группу захвата

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

r'(\d)(?!\1)((\d)\3)(?!\3)(?=\d)'

Re engine

Выполняются следующие операции.

(\d)    : match a digit in capture group 1
(?!\1)  : next character does not equal last character
(       : begin capture group 2
  (\d)  : match a digit in capture group 3
  \3    : match the content of capture group 3
)       : end capture group 2
(?!\3)  : next character does not equal last character
(?=\d)  : next character is a digit

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

Мы используем следующее регулярное выражение для сопоставления строки.

r'(\d)(?=\1)|\d(?=(\d)(?!\2))|\d(?=\d(\d)\3)|\d(?=(\d{2})\d)'

Когда есть совпадение, мы не обращаем внимания на то, какой символ был сопоставлен, а проверяем содержимое группы захвата 4 ((\d{2})) , как я объясню ниже.

Уловка в действии

Первые три компонента чередования соответствуют способам, которым строка из четырех цифр может не иметь Имейте в виду, что вторая и третья цифры равны, первая и вторая не равны, а третья и четвертая равны. Это:

(\d)(?=\1)        : assert first and second digits are equal    
\d(?=(\d)(?!\2))  : assert second and third digits are not equal
\d(?=\d(\d)\3)    : assert third and fourth digits are equal

Отсюда следует, что если есть совпадение di git и первые три части чередования терпят неудачу, последняя часть (\d(?=(\d{2})\d)) должна быть успешной, и группа захвата он содержит (# 4) должен содержать две одинаковые цифры, которые имеют требуемые свойства. (Последний \d необходим, чтобы утверждать, что за парой интересующих цифр следует di git.)

Если есть совпадение, как мы определяем, является ли последняя часть чередования тот, который соответствует?

Когда это регулярное выражение соответствует di git, нас не интересует, что это было за di git. Вместо этого мы ищем группу 4 ((\d{2})). Если эта группа пуста, мы заключаем, что один из первых трех компонентов чередования соответствует di git, что означает, что две цифры, следующие за сопоставленным di git, не обладают свойствами, равными и не равными цифры, предшествующие и следующие за ними.

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

1. Переместите курсор для получения подробных объяснений.

34 голосов
/ 19 июня 2020

С регулярным выражением гораздо удобнее использовать модуль PyPi regex с шаблоном на основе (*SKIP)(*FAIL):

import regex
rx = r'(\d)\1{2,}(*SKIP)(*F)|(\d)\2'
l = ["123456678", "1234566678"]
for s in l:
  print(s, bool(regex.search(rx, s)) )

См. Python demo . Вывод:

123456678 True
1234566678 False

Детали регулярного выражения

  • (\d)\1{2,}(*SKIP)(*F) - a di git, а затем два или более вхождения одного и того же di git
  • | - или
  • (\d)\2 - a di git и затем тот же di git.

Дело в том, чтобы сопоставить все фрагменты из трех или более одинаковых цифр и пропустить их, а затем сопоставить фрагмент из двух одинаковых цифр.

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

10 голосов
/ 19 июня 2020

Вдохновленный ответом или Wiktor Stribiew, другой вариант использования чередования с re заключается в проверке существования группы захвата, которая содержит положительное совпадение для двух одинаковых цифр, не окруженных одним и тем же di git.

В этом случае проверьте группу 3.

((\d)\2{2,})|\d(\d)\3(?!\3)\d

Regex demo | Python демонстрация

  • ( Захват группа 1
    • (\d)\2{2,} Захват группа 2 , сопоставить 1 di git и повторить тот же di git 2+ раза
  • ) Закрыть группу
  • | Или
  • \d(\d) Сопоставьте di git, захватите di git в группе 3
  • \3(?!\3)\d Сопоставьте то же di git, что и в группе 3. Сопоставьте 4 th di git, но это не должно совпадать с группой 3 di git

Например

import re

pattern = r"((\d)\2{2,})|\d(\d)\3(?!\3)\d"
strings = ["123456678", "12334566", "12345654554888", "1221", "1234566678", "1222", "2221", "66", "122", "221", "111"]

for s in strings:
    match = re.search(pattern, s)
    if match and match.group(3):
        print ("Match: " + match.string)
    else:
        print ("No match: " + s)

Выход

Match: 123456678
Match: 12334566
Match: 12345654554888
Match: 1221
No match: 1234566678
No match: 1222
No match: 2221
No match: 66
No match: 122
No match: 221
No match: 111

Если, например, можно сопоставить только 2 или 3 цифры, вы можете проверить группу 2

(\d)\1{2,}|(\d)\2

Python demo

5 голосов
/ 19 июня 2020

Вы также можете использовать простой способ.

import re
l=["123456678",
"1234566678",
"12334566 "]
for i in l:
    matches = re.findall(r"((.)\2+)", i)
    if any(len(x[0])!=2 for x in matches):
        print "{}-->{}".format(i, False)
    else:
        print "{}-->{}".format(i, True)

Вы можете настроить это в соответствии с вашими правилами.

Вывод:

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