2008-10-15 18 views
7

trạng:Chụp nội dung của một regex và xóa chúng, hiệu quả

  • văn bản: một chuỗi
  • R: a regex phù hợp với một phần của chuỗi. Điều này có thể tốn kém để tính toán.

Tôi muốn xóa cả các đối sánh R khỏi văn bản và xem nội dung chúng thực sự chứa. Hiện tại, tôi làm như sau:

import re 
ab_re = re.compile("[ab]") 
text="abcdedfe falijbijie bbbb laifsjelifjl" 
ab_re.findall(text) 
# ['a', 'b', 'a', 'b', 'b', 'b', 'b', 'b', 'a'] 
ab_re.sub('',text) 
# 'cdedfe flijijie lifsjelifjl' 

Điều này chạy regex hai lần, gần như tôi có thể nói. Có một kỹ thuật để làm tất cả trên vượt qua, có lẽ bằng cách sử dụng re.split? Nó có vẻ như với các giải pháp dựa trên phân chia tôi cần phải làm regex ít nhất hai lần là tốt.

+0

Ít nhất 3 bộ câu trả lời hay. Mỏ nhanh và đơn giản, sử dụng re.split(). Deestan của exposes tất cả các thông tin về các trận đấu bằng cách sử dụng finditer(), và Jon Cage cho thấy chức năng có thể được sử dụng trong re.sub, đó là một thông minh. –

Trả lời

4
import re 

r = re.compile("[ab]") 
text = "abcdedfe falijbijie bbbb laifsjelifjl" 

matches = [] 
replaced = [] 
pos = 0 
for m in r.finditer(text): 
    matches.append(m.group(0)) 
    replaced.append(text[pos:m.start()]) 
    pos = m.end() 
replaced.append(text[pos:]) 

print matches 
print ''.join(replaced) 

Đầu ra:

['a', 'b', 'a', 'b', 'b', 'b', 'b', 'b', 'a'] 
cdedfe flijijie lifsjelifjl 
+0

Bạn có thể sử dụng một danh sách thay cho StringIO, và tham gia vào cuối cùng, nếu bạn muốn giữ nó đơn giản. – Tomalak

+0

Tomalak: Vâng, điều đó sẽ đơn giản hơn. Một chút hồ sơ thử nghiệm cho thấy rằng nó thực sự là nhanh hơn quá, ít nhất là trên đầu vào thử nghiệm của tôi. – Deestan

+0

Không thực sự làm tôi ngạc nhiên. Tôi đã gõ về cơ bản cùng một điều, bạn chỉ xảy ra được nhanh hơn.;-) – Tomalak

0

Bạn có thể sử dụng tính năng chia tách với chụp các dấu ngoặc đơn. Nếu bạn làm như vậy, thì văn bản của tất cả các nhóm trong mẫu cũng được trả về như một phần của danh sách kết quả (từ python doc).

Vì vậy, các mã sẽ

import re 
ab_re = re.compile("([ab])") 
text="abcdedfe falijbijie bbbb laifsjelifjl" 
matches = ab_re.split(text) 
# matches = ['', 'a', '', 'b', 'cdedfe f', 'a', 'lij', 'b', 'ijie ', 'b', '', 'b', '', 'b', '', 'b', ' l', 'a', 'ifsjelifjl'] 

# now extract the matches 
Rmatches = [] 
remaining = [] 
for i in range(1, len(matches), 2): 
    Rmatches.append(matches[i]) 
# Rmatches = ['a', 'b', 'a', 'b', 'b', 'b', 'b', 'b', 'a'] 

for i in range(0, len(matches), 2): 
    remaining.append(matches[i]) 
remainingtext = ''.join(remaining) 
# remainingtext = 'cdedfe flijijie lifsjelifjl' 
+0

Tất cả mã "if text == a" ở đây thực hiện regex lần thứ hai. Nếu regex đơn giản như [ab], thì toàn bộ câu hỏi này sẽ là tranh luận. :) Mặc dù nỗ lực tốt, và nó thúc đẩy suy nghĩ của tôi một chút, vào các giải pháp lọc. –

+0

Đúng, cố định nó bằng cách nhận thấy rằng các kết quả trùng khớp có văn bản bị loại bỏ và bỏ đi, bao gồm các chuỗi rỗng, vì vậy giải pháp trên đơn giản hơn và regex chỉ chạy một lần :) –

+0

Đủ công bằng. Cắt lát là đơn giản hơn mặc dù :) Tôi đã có cùng một nhận thức về việc thay thế token-phù hợp với điều quá! Cảm ơn gợi ý. –

3

câu trả lời được sửa đổi của tôi, sử dụng re.split(), mà làm những việc trong một regex pass:

import re 
text="abcdedfe falijbijie bbbb laifsjelifjl" 
ab_re = re.compile("([ab])") 
tokens = ab_re.split(text) 
non_matches = tokens[0::2] 
matches = tokens[1::2] 

(chỉnh sửa: đây là một phiên bản hoàn chỉnh chức năng)

def split_matches(text,compiled_re): 
    ''' given a compiled re, split a text 
    into matching and nonmatching sections 
    returns m, n_m, two lists 
    ''' 
    tokens = compiled_re.split(text) 
    matches = tokens[1::2] 
    non_matches = tokens[0::2] 
    return matches,non_matches 

m,nm = split_matches(text,ab_re) 
''.join(nm) # equivalent to ab_re.sub('',text) 
+0

Lưu ý rằng việc biên dịch lại phải là một 'chụp lại' với các xung quanh toàn bộ mớ hỗn độn, hoặc điều này sẽ không hoạt động đúng. –

+0

Hmm? Làm việc cho tôi mà không có dấu ngoặc đơn. – Deestan

4

gì về điều này:

import re 

text = "abcdedfe falijbijie bbbb laifsjelifjl" 
matches = [] 

ab_re = re.compile("[ab]") 

def verboseTest(m): 
    matches.append(m.group(0)) 
    return '' 

textWithoutMatches = ab_re.sub(verboseTest, text) 

print matches 
# ['a', 'b', 'a', 'b', 'b', 'b', 'b', 'b', 'a'] 
print textWithoutMatches 
# cdedfe flijijie lifsjelifjl 

Các 'repl' lập luận của re.sub chức năng có thể là một chức năng để bạn có thể báo cáo hoặc lưu các trận đấu từ đó và bất kỳ chức năng nào trả về là 'phụ' sẽ thay thế.

Chức năng có thể dễ dàng được sửa đổi để thực hiện nhiều hơn nữa! Hãy xem the re module documentation trên docs.python.org để biết thêm thông tin về những điều khác có thể.

+0

Đó là một giải pháp rất thông minh. Tôi không biết bạn có thể sử dụng các hàm như một đối số đầu tiên cho hàm phụ. –

+0

Cảm ơn, tôi đã khá chuffed với nó đơn giản khi tôi nhận ra bạn có thể gọi một chức năng :-) –

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