2011-02-05 59 views
9

Cách thức hoạt động của regex trong Python rất khó hiểu khiến nó trở nên tức giận hơn với mỗi giây trôi qua. Dưới đây là vấn đề của tôi:Tại sao regex của tôi lại phù hợp với r'string 'nhưng không phải' chuỗi 'bằng Python?

Tôi hiểu rằng điều này sẽ cho kết quả là:

re.search(r'\bmi\b', 'grand rapids, mi 49505) 

trong khi điều này không:

re.search('\bmi\b', 'grand rapids, mi 49505) 

Và đó là okay. Tôi nhận được nhiều điều đó. Bây giờ, tôi có một biểu hiện thường xuyên đó là được tạo ra như thế này:

regex = '|'.join(['\b' + str(state) + '\b' for state in states]) 

Nếu bây giờ tôi làm re.search(regex, 'grand rapids, mi 49505'), nó thất bại với cùng lý do thứ hai search() ví dụ của tôi thất bại.

Câu hỏi của tôi: Có cách nào để làm những gì tôi đang cố gắng làm không?

+3

Lưu ý: Các dấu ngoặc vuông là dư thừa (trên thực tế, có hại: sự khác biệt giữa 'O (n)' và 'O (1)' bộ nhớ tiêu thụ), thay vào đó, sử dụng một [biểu thức máy phát điện] (http://docs.python.org/tutorial/classes.html#generator-expressions). – delnan

Trả lời

14

Các anwser tự

regex = '|'.join([r'\b' + str(state) + r'\b' for state in states]) 

Lý do đằng sau này là các Tiền tố 'r' yêu cầu Python không phân tích chuỗi mà bạn truyền cho nó. Nếu bạn không đặt 'r' trước chuỗi, Python sẽ cố gắng biến bất kỳ từ trước nào bằng '\' thành một char đặc biệt, để cho phép bạn nhập các dòng ngắt (\ n), các tab (\ t) và như vậy dễ dàng.

Khi bạn làm '\b', bạn yêu cầu Python tạo chuỗi, phân tích và biến '\ b' thành 'backspace', trong khi bạn làm r'\b', Python chỉ lưu '\' rồi 'b' và điều này là những gì bạn muốn với regex. Luôn sử dụng 'r' cho chuỗi được sử dụng làm mẫu regex.

Ký hiệu 'r' được gọi là 'chuỗi thô', nhưng điều đó gây hiểu lầm, vì không có chuỗi nào như chuỗi thô trong nội bộ Python. Chỉ cần nghĩ về nó như một cách để nói với Python để tránh bị quá thông minh.

Có một ký hiệu khác trong Python < 3.0, u'string ', điều đó sẽ yêu cầu Python lưu trữ chuỗi dưới dạng unicode. Bạn có thể kết hợp cả hai: ur"é\n" sẽ lưu trữ "\ bé" làm unicode, trong khi u"é\n" sẽ lưu trữ "é" rồi ngắt dòng.

Một số cách để cải thiện mã của bạn:

regex = '|'.join(r'\b' + str(state) + r'\b' for state in states) 

Loại bỏ các phụ []. Nó nói với Python không lưu trữ trong bộ nhớ danh sách các giá trị mà bạn đang tạo ra. Chúng tôi có thể làm điều đó ở đây vì chúng tôi không có kế hoạch sử dụng lại danh sách bạn đang tạo vì bạn sử dụng trực tiếp trong số join() và không có nơi nào khác.

regex = '|'.join(r'\b%s\b' % state for state in states) 

Điều này sẽ tự động chuyển đổi chuỗi và ngắn hơn và sạch hơn.Khi bạn định dạng chuỗi bằng Python, hãy nghĩ về số % operator.

Nếu các trạng thái chứa danh sách mã zip của tiểu bang, thì phải lưu trữ dưới dạng chuỗi, chứ không phải là int. Trong trường hợp đó, bạn có thể bỏ qua loại truyền và rút ngắn hơn nữa:

regex = r'\b%s\b' % r'\b|\b'.join(states) 

Cuối cùng, bạn có thể không cần regex chút nào. Nếu tất cả các bạn quan tâm là để kiểm tra xem một trong những zip code là trong chuỗi nhất định, bạn chỉ có thể sử dụng in (kiểm tra nếu một mục là trong một iterable, như thế nào nếu một chuỗi là trong danh sách):

matches = [s for s in states if s in 'grand rapids, mi 49505'] 

Từ cuối

Tôi hiểu bạn có thể thất vọng khi học một ngôn ngữ mới, nhưng dành thời gian để đưa ra một tiêu đề phù hợp cho câu hỏi của bạn. Trong trang web này, tiêu đề phải kết thúc bằng dấu chấm hỏi và cung cấp chi tiết cụ thể về sự cố.

+0

Cách về một lời giải thích? – delnan

+1

Tiếng Pháp của bạn đang hiển thị. Danh sách> danh sách. – ash

+2

Chết tiệt. Chờ đã, tôi có thể là người Ý! –

4

Giải pháp là giải pháp bạn đã sử dụng trong ví dụ trên: chuỗi thô.

regex = '|'.join(r'\b' + str(state) + r'\b' for state in states) 

(Lưu ý rằng tôi cũng loại bỏ các dấu ngoặc thêm, biến danh sách hiểu thành một biểu thức máy phát điện.)

+0

Tại sao cần dây thô? – cledoux

+1

Chỉ cần '\ b' trong một chuỗi được hiểu là một chuỗi thoát và tạo ra một mã điều khiển BELL (tôi nghĩ). Khi bạn muốn regex (kết quả) bao gồm một chuỗi thoát, tuy nhiên, bạn cần đảm bảo rằng toàn bộ chuỗi được bao gồm trong chuỗi. Vì vậy, bạn cần phải thoát khỏi dấu gạch chéo ngược một cách tách biệt: '\\ b' dẫn đến' \ b' trong chuỗi. – poke

+0

@ char8705: thêm lý do cho điều đó trong anwser của tôi. –

2

Điều quan trọng là hiểu sự khác biệt giữa '\ b' và r '\ b'. Gõ những kết quả trong IDLE sản lượng này:

>>> '\b' 
'\x08' 
>>> r'\b' 
'\\b' 

Vì vậy, bất cứ khi nào bạn gõ vào một dấu chéo ngược trong một regex, bạn nên thoát khỏi nó bằng cách sử dụng ký hiệu chuỗi thô.

+0

Điều này gây hiểu lầm. Python không lưu trữ r '\ b' dưới dạng '\\ b' trong nội bộ. Đó là IDLE và hầu hết vỏ Python hiển thị nó theo cách đó để cung cấp cho bạn một đầu mối về những gì bên trong. Nhưng bạn sẽ không nhận được như vậy nếu bạn in. Điều này sẽ gây nhầm lẫn cho tất cả những người mới. –

0

Hãy phá vỡ hai chuỗi những xuống:

r'\bmi\b' 

Python giải thích chuỗi đàn miễn Sáu ký tự (dấu chéo ngược, chữ B, vv). Chuỗi thô ngăn chặn bản dịch của Python là \ b vào một không gian ẩn.

tái giải thích hai nhân vật \b như một break từ.

'\bmi\b' 

Python giải thích chuỗi đàn miễn Bốn ký tự (backspace, chữ B, vv).
re hiện không thấy gì đặc biệt để diễn giải và tìm kiếm bốn ký tự theo nghĩa đen đó.

Vì vậy, việc xây dựng bên dưới đang tìm kiếm backspaces, không phá vỡ từ:

regex = '|'.join(['\b' + str(state) + '\b' for state in states]) 

Hãy thử điều này (thả str, tiểu bang đã phải là một string):

nghỉ
regex = '|'.join([r'\b' + state + r'\b' for state in states]) 

Từ doesn' t cần được xử lý trong mọi biểu thức OR.Kéo nó ra đơn giản hoá các tham gia:

regex = r'\b(' + '|'.join(states) + r')\b' 

Kể từ Pythonistas thường tiết kiệm nụ cười trên regexes, cũng có thể tạo ra một thể đọc được một:

import re 

pattern = re.compile(r''' 
    (?ix) # ignore case, verbose 
    \b # word break 
    ( # begin group 1 
    AL|AK|AZ|AR|CA|CO|CT|DE|FL|GA| 
    HI|ID|IL|IN|IA|KS|KY|LA|ME|MD| 
    MA|MI|MN|MS|MO|MT|NE|NV|NH|NJ| 
    NM|NY|NC|ND|OH|OK|OR|PA|RI|SC| 
    SD|TN|TX|UT|VT|VA|WA|WV|WI|WY 
    )  # end group 1 
    \b # word break 
    ''') 

m = pattern.search('Grand Rapids, MI 49505') 
if m: 
    print m.group(1) 
+0

"Kể từ khi Pythonistas thường cau mày trên regexes ..." Thú vị. Làm thế nào mà? Bạn sẽ sử dụng cái gì? –

Các vấn đề liên quan