Tìm kiếm ký tự đại diện Python trong chuỗi


78

Hãy nói rằng tôi có một danh sách

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

làm cách nào để yêu cầu người dùng thực hiện tìm kiếm theo ký tự đại diện?

Tìm kiếm từ: 'th_s'

Sẽ trả lại 'cái này'

Câu trả lời:


55

Biểu thức chính quy có lẽ là giải pháp dễ dàng nhất cho vấn đề này:

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
Điều này không nên được chấp nhận câu trả lời (regex không xử lý trận đấu wildcard) - ví dụ như tôi đang tìm kiếm giải pháp wildcard tinh khiết (do @phihag) và tôi đã quen thuộc với regex
jirislav

10
làm thế nào để regex không xử lý các trận đấu ký tự đại diện ??
john ktejik

164

Sử dụng fnmatch:

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

Nếu bạn muốn cho phép _dưới dạng ký tự đại diện, chỉ cần thay thế tất cả các dấu gạch dưới bằng '?'(cho một ký tự) hoặc *(cho nhiều ký tự).

Nếu bạn muốn người dùng của mình sử dụng các tùy chọn lọc mạnh hơn nữa, hãy cân nhắc cho phép họ sử dụng các cụm từ thông dụng .


1
Tuyệt :) Nhưng tôi hiểu rằng nó được điều chỉnh để phù hợp với các đường dẫn, nó sẽ không hài hước nếu có dấu gạch chéo? Ngoài ra, nó có hỗ trợ **ký tự đại diện không? (e-> Tôi đã kiểm tra các tài liệu- nó không xử lý các dấu gạch chéo khác nhau và vì vậy **ký tự đại diện thậm chí không cần thiết ở đây).
Kos,

Tài liệu nói rằng đó fnmatchlà "Đối sánh mẫu tên tệp Unix". Nhưng tôi vừa thử nó, và nó có vẻ hoạt động trên Windows. Đây là hành vi may mắn không xác định hay được fnmatchhỗ trợ trên Windows?
cowlinator

1
@cowlinator Phương pháp đối sánh tên tệp được gọi là đối sánh tệp Unix vì nó có nguồn gốc từ Unix, nhưng nó độc lập với hệ điều hành, giống như cách mà các chữ số Ả Rập cũng hoạt động trong tiếng Anh.
phihag

Bộ lọc chỉ hoạt động với danh sách dưới dạng đối số. Trong trường hợp chuỗi tôi cần một re.
Timo


2

Bạn có nghĩa là bất kỳ cú pháp cụ thể cho các ký tự đại diện? Thường *là viết tắt của "một hoặc nhiều" ký tự và ?là viết tắt của một.

Cách đơn giản nhất có lẽ là dịch một biểu thức ký tự đại diện thành một biểu thức chính quy, sau đó sử dụng nó để lọc kết quả.


4
Các fnmatchmô-đun có chức năng dịch trận ký tự đại diện vào biểu thức thông thường:fnmatch.translate
Peter Gỗ

Có vẻ như * là từ 0 đến nhiều hơn, ít nhất nó cũng phù hợp với tôi vì tôi cần một chuỗi mà đôi khi KHÔNG có ký tự được tìm kiếm ..
Timo

0

Ý tưởng tương tự như Yuushi trong việc sử dụng biểu thức chính quy, nhưng điều này sử dụng phương pháp findall trong thư viện re thay vì đọc danh sách:

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

1
bạn vẫn cần lấy chuỗi từ một mảng bằng cách nào đó.
BartBiczBoży

0

Tại sao bạn không chỉ sử dụng chức năng tham gia? Trong một regex findall () hoặc group (), bạn sẽ cần một chuỗi để:

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

Hàm join () cho phép bạn biến đổi một danh sách trong một chuỗi. Dấu nháy đơn trước khi tham gia là những gì bạn sẽ đặt ở giữa mỗi chuỗi trong danh sách. Khi bạn thực thi phần mã này ('' .join (l)), bạn sẽ nhận được:

'Đây chỉ là một bài kiểm tra'

Vì vậy, bạn có thể sử dụng hàm findal ().

Tôi biết mình đã trễ 7 năm, nhưng gần đây tôi đã tạo một tài khoản vì tôi đang học và những người khác có thể có cùng câu hỏi. Tôi hy vọng điều này sẽ giúp bạn và những người khác.


Cập nhật các bình luận sau @ 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)

giải pháp này sẽ không phá vỡ nếu có từ "th" và "s"? (bằng cách tham gia, bạn sẽ nhận được "thứ s", với sẽ là một so khớp hợp lệ. Ngoài ra, nếu đã có trong danh sách một chuỗi với khoảng trắng như "this is", giải pháp của bạn sẽ trả về sự kiện "this", nó không có phần tử trong danh sách exacly phù hợp này có thể là một vấn đề..
Félix Brunet

@ FélixBrunet, bạn hoàn toàn đúng! Tôi đã viết một đoạn mã có vòng lặp để tránh các vòng lặp mà bạn đã đề cập! Tôi đang trong quá trình học tập như thế nào, tôi tin rằng điều này có thể được cải thiện. Nếu bạn có điều gì đó để thêm, vui lòng miễn phí. Cảm ơn bạn.
Michel Soares

-6

Phương pháp dễ dàng là thử os.system:

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

11
Vậy ... điều gì sẽ xảy ra nếu tôi đặt text = "die | rm -rf /"?
WoLfulus

Hai vấn đề. Trước tiên, bạn không cần phải trình bày để thực hiện một chức năng mà python hoạt động tốt. Thứ hai, không phải tất cả các hệ điều hành đều có grep.
River-Claire Williamson
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.