Пошук підстановок Python у рядку


78

Скажімо, у мене є список

list = ['this','is','just','a','test']

як я можу запросити користувача здійснити пошук підстановок?

Шукати слово: 'th_s'

Поверне "це"

Відповіді:


55

Регулярні вирази є, мабуть, найпростішим рішенням цієї проблеми:

import re
regex = re.compile('th.s')
l = ['this', 'is', 'just', 'a', 'test']
matches = [string for string in l if re.match(regex, string)]

7
Цю відповідь не слід приймати (регулярний вираз не обробляє збіги з підстановкою) - напр., Я шукаю чистого розв’язання підстановок (надано @phihag), і я вже знайомий із регулярним виразом
jirislav,

10
як регулярний вираз не обробляє підстановочні збіги ??
Джон Ктеджік,

164

Використання fnmatch:

import fnmatch
lst = ['this','is','just','a','test']
filtered = fnmatch.filter(lst, 'th?s')

Якщо ви хочете дозволити _підстановку, просто замініть усі підкреслення на '?'(для одного символу) або *(для кількох символів).

Якщо ви хочете, щоб ваші користувачі використовували ще більш потужні параметри фільтрації, подумайте про те, щоб дозволити їм використовувати регулярні вирази .


1
Класно :) Але я розумію, що він налаштований на відповідні шляхи, чи не буде діяти смішно, якщо є скісні риски? Крім того, чи підтримує він **шаблон? (e-> Я перевірив документи - він не по-різному ставиться до скісних рисок, тому **підстановка тут навіть не потрібна).
Кос

У документації зазначено, що fnmatch"Відповідність шаблону імені файлу Unix". Але я щойно спробував, і, схоже, це працює в Windows. Це щаслива невизначена поведінка чи fnmatchпідтримується в Windows?
cowlinator

1
@cowlinator Метод узгодження імен файлів називається Unix file matching, оскільки він походить від Unix, але він не залежить від операційної системи, так само, як арабські цифри також працюють англійською мовою.
phihag

Фільтр просто працює зі списками як аргумент. У випадку рядка мені потрібне повторне.
Тимо


2

Ви маєте на увазі якийсь конкретний синтаксис для символів підстановки? Зазвичай *розшифровується як "один або багато" символів і ?позначає один.

Можливо, найпростіший спосіб - перевести вираз підстановки у регулярний вираз, а потім використовувати його для фільтрації результатів.


4
fnmatchМодуль має функцію перекладу підстановочні матчів в регулярних виразах:fnmatch.translate
Пітер Вуд

Здається, * * від нуля до більше, принаймні це працює для мене, тому що мені потрібна рядок, яка іноді НЕ має шуканого символу ..
Тимо,

0

Та сама ідея, що і Юуші при використанні регулярних виразів, але тут використовується метод findall у бібліотеці re замість розуміння списку:

import re
regex = re.compile('th.s')
l = ['this', 'is', 'just', 'a', 'test']
matches = re.findall(regex, string)

1
вам все одно потрібно якось отримати рядок з масиву.
BartBiczBoży

0

Чому ви просто не використовуєте функцію приєднання? У регулярному виразі findall () або group () вам знадобиться рядок так:

import re
regex = re.compile('th.s')
l = ['this', 'is', 'just', 'a', 'test']
matches = re.findall(regex, ' '.join(l)) #Syntax option 1
matches = regex.findall(' '.join(l)) #Syntax option 2

Функція join () дозволяє перетворити список у рядок. Одинарна лапка перед приєднанням - це те, що ви помістите в середину кожного рядка у списку. Після виконання цієї частини коду ('' .join (l)) ви отримаєте таке:

'це просто тест'

Таким чином, ви можете використовувати функцію findal ().

Я знаю, що запізнююсь на 7 років, але нещодавно створив обліковий запис, оскільки навчаюсь, і у інших людей може виникнути таке саме питання. Сподіваюся, це допоможе вам та іншим.


Оновити після коментарів @ FélixBrunet:

import re
regex = re.compile(r'th.s')
l = ['this', 'is', 'just', 'a', 'test','th','s', 'this is']

matches2=[] #declare a list
for i in range(len(l)): #loop with the iterations = list l lenght. This avoid the first item commented by @Felix
if regex.findall(l[i]) != []: #if the position i is not an empty list do the next line. PS: remember regex.findall() command return a list.
    if l[i]== ''.join(regex.findall(l[i])): # If the string of i position of l list = command findall() i position so it'll allow the program do the next line - this avoid the second item commented by @Félix
        matches2.append(''.join(regex.findall(l[i]))) #adds in the list just the string in the matches2 list

print(matches2)

чи не розірветься це рішення, якби були слова "й" та "s"? (приєднавшись, ви отримаєте "й", при цьому буде дійсним збігом. також, якщо в списку вже був рядок із пробілом, як "це", ваше рішення поверне подію "це", якщо його не було елемент у списку дуже підходить. це може бути проблемою.
Фелікс Брунет,

@ FélixBrunet, ти абсолютно прав! Я написав код із циклом, щоб уникнути ітен, про які ви згадали! Як я переживаю навчальний процес, я вважаю, що це можна покращити. Якщо у вас є що-небудь ще, щоб додати, будь ласка, вибудьте безкоштовно. Дякую.
Мішель Соарес

-6

Простий спосіб - спробувати os.system:

import os
text = 'this is text'
os.system("echo %s | grep 't*'" % text)

11
Отже ... що станеться, якщо я поміщу text = "die | rm -rf /"?
WoLfulus

Дві проблеми. По-перше, вам не потрібно вводити оболонки, щоб виконати функцію, яку python робить добре. По-друге, не всі ОС мають grep.
Рівер-Клер Вільямсон,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.