Захватите целое число в строке и используйте его как часть регулярного выражения

У меня есть строка:

s = ".,-2gg,,,-2gg,-2gg,,,-2gg,,,,,,,,t,-2gg,,,,,,-2gg,t,,-1gtt,,,,,,,,,-1gt,-3ggg"

и регулярное выражение, которое я использую

import re
delre = re.compile('-[0-9]+[ACGTNacgtn]+') #this is almost correct
print (delre.findall(s))

Это возвращает:

['-2gg', '-2gg', '-2gg', '-2gg', '-2gg', '-2gg', '-1gtt', '-1gt', '-3ggg']

Но -1gtt и -1gt не являются желаемыми совпадениями. Целое число в этом случае определяет, сколько последующих символов должно соответствовать, поэтому желаемый результат для этих двух совпадений будет -1g и -1g соответственно.

Есть ли способ получить целое число после тире и динамически определить регулярное выражение так, чтобы оно соответствовало такому количеству и только такому количеству последующих символов?

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

jonrsharpe 20.08.2024 19:21

Существует ли предел размера этого целого числа для допустимых совпадений?

Scott Hunter 20.08.2024 19:21

@ScottHunter почти во всех случаях можно предположить, что целое число <50

Ryan 20.08.2024 19:23

Таким образом, вы можете создать шаблон для каждого конкретного целого числа и ИЛИ их вместе. Возможно, это немного непрактично за ~50, но это ваше дело. Предложение @jonrsharpe, вероятно, подойдет.

Scott Hunter 20.08.2024 19:46
Почему в 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
4
51
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

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

import re

# surround [0-9]+ and [ACGTNacgtn]+ in parentheses to create two capture groups
delre = re.compile('-([0-9]+)([ACGTNacgtn]+)')  

s = ".,-2gg,,,-2gg,-2gg,,,-2gg,,,,,,,,t,-2gg,,,,,,-2gg,t,,-1gtt,,,,,,,,,-1gt,-3ggg"

# each match should be a tuple of (number, letter(s)), e.g. ('1', 'gtt') or ('2', 'gg')
for number, bases in delre.findall(s):
    # print the number, then use slicing to truncate the string portion
    print(f'-{number}{bases[:int(number)]}')

Это печатает

-2gg
-2gg
-2gg
-2gg
-2gg
-2gg
-1g
-1g
-3ggg

Скорее всего, вы захотите сделать что-то кроме print, но вы можете форматировать совпадающие строки так, как вам нужно!

ПРИМЕЧАНИЕ. Это не работает в тех случаях, когда за целым числом следует меньше совпадающих символов, чем указано, например. -10agcta по-прежнему соответствует, хотя содержит всего 5 символов.

приятно, спасибо! можно с уверенностью предположить, что целое число и последующее количество оснований всегда совпадают. Строка в данном случае выводится командой samtoolsmpileup, поэтому, вероятно, она была тщательно протестирована.

Ryan 20.08.2024 19:49

@Райан Рад, что смог помочь! Если вы уверены, что поступающие данные всегда будут соответствовать друг другу, то это должно быть полностью работоспособно. Я не знаком с samtools или mpileup, но эти буквы кричали мне о ДНК, поэтому я предположил.

JRiggles 20.08.2024 19:51

Еще одно альтернативное решение с использованием re.sub, которое делает это без цикла:

import re

# surround [0-9]+ and [ACGTNacgtn]+ in parentheses to create two capture groups
delre = re.compile('[^-]*-([0-9]+)([ACGTNacgtn]+)[^-]*')  

s = ".,-2gg,,,-2gg,-2gg,,,-2gg,,,,,,,,t,-2gg,,,,,,-2gg,t,,-1gtt,,,,,,,,,-1gt,-3ggg"

print (re.sub(delre, lambda m: f"-{m.group(1)}{m.group(2)[:int(m.group(1))]}\n", s))

Выход:

-2gg
-2gg
-2gg
-2gg
-2gg
-2gg
-1g
-1g
-3ggg

или же, если вы хотите вывести результат в массиве, используйте:

arr = re.sub(delre, lambda m: f"-{m.group(1)}{m.group(2)[:int(m.group(1))]} ", s).strip().split()
print (arr)

['-2gg', '-2gg', '-2gg', '-2gg', '-2gg', '-2gg', '-1g', '-1g', '-3ggg']

.strip() не нужен.

no comment 21.08.2024 01:22

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