2013-08-27 41 views
5

Câu hỏi phần 1Python: re.compile và re.sub

Tôi có tập tin f1 này:

<something @37> 
<name>George Washington</name> 
<a23c>Joe Taylor</a23c> 
</something @37> 

và tôi muốn re.compile nó rằng nó trông giống như f1 này: (với không gian)

George Washington Joe Taylor 

tôi đã thử mã này nhưng nó kinda xóa tất cả mọi thứ:

import re 
file = open('f1.txt') 
fixed = open('fnew.txt','w') 
text = file.read() 

match = re.compile('<.*>') 
for unwanted in text: 
    fixed_doc = match.sub(r' ',text) 

fixed.write(fixed_doc) 

Đoán của tôi là dòng re.compile nhưng tôi không chắc chắn nên làm gì với nó. Tôi không được phép sử dụng tiện ích mở rộng của bên thứ ba. Bất kỳ ý tưởng?


Câu hỏi phần 2

Tôi có một câu hỏi khác về so sánh 2 file tôi có mã này từ Alfe:

from collections import Counter 

def test(): 
    with open('f1.txt') as f: 
     contentsI = f.read() 
    with open('f2.txt') as f: 
     contentsO = f.read() 

    tokensI = Counter(value for value in contentsI.split() 
         if value not in []) 
    tokensO = Counter(value for value in contentsO.split() 
         if value not in []) 
    return not (tokensI - tokensO) and not (set(tokensO) - set(tokensI)) 

Có thể thực hiện các re.compile và re.sub trong phần 'if value not in []'?

+0

Xin chào. Trong vấn đề đầu tiên, ý định của bạn là xóa TẤT CẢ những gì trông giống như các thẻ, hoặc các thẻ thực sự xác định một phần tử của một ngôn ngữ đánh dấu? Tôi sử dụng từ 'nguyên tố' theo nghĩa chính xác và đúng của nó, có nghĩa là 'thẻ bắt đầu + nội dung phần tử + thẻ kết thúc'. - Ngoài ra, khi bạn tiếp xúc với nội dung của tập tin f, có những dòng trong đó, đó là để nói dòng mới trong đó. Những gì bạn cho thấy là kết quả mong muốn là một chuỗi trong đó không có thêm dòng mới. Nó thực sự là những gì bạn muốn hoặc bạn muốn giữ cấu trúc trong dòng? – eyquem

+0

Bạn muốn nói gì với '' nếu value not in []) ''? Hiện nay nó không có ý nghĩa, vì luôn luôn không có gì trong một danh sách void. Bạn muốn làm gì khi so sánh các tệp? Nó không phải là rất rõ ràng – eyquem

Trả lời

13

tôi sẽ giải thích những gì xảy ra với mã của bạn:

import re 
file = open('f1.txt') 
fixed = open('fnew.txt','w') 
text = file.read() 

match = re.compile('<.*>') 
for unwanted in text: 
    fixed_doc = match.sub(r' ',text) 

fixed.write(fixed_doc) 

Các hướng dẫn text = file.read() tạo ra một đối tượng văn bản loại chuỗi tên text.
Lưu ý rằng tôi sử dụng các ký tự in đậm văn bản để thể hiện OBJECT và text để thể hiện tên == IDENTIFIER của đối tượng này.
Do hậu quả của hướng dẫn for unwanted in text:, số nhận dạng unwanted được gán liên tiếp cho từng ký tự được tham chiếu bởi đối tượng văn bản.

Bên cạnh đó, re.compile('<.*>') tạo ra một đối tượng kiểu RegexObject (mà tôi personnaly gọi biên soạn) regex hoặc đơn giản là regex, <.*> là chỉ mô hình regex).
Bạn chỉ định đối tượng regex đã biên dịch này cho số nhận dạng match: đây là một phương pháp rất xấu, bởi vì match đã là tên của một phương thức của các đối tượng regex nói chung và đối tượng bạn đã tạo cụ thể, sau đó bạn có thể viết match.match lỗi.
match cũng là tên của chức năng của mô-đun re.
Việc sử dụng tên này cho nhu cầu cụ thể của bạn là rất khó hiểu. Bạn phải tránh điều đó.

Có lỗi tương tự với việc sử dụng file làm tên cho trình xử lý tệp của tệp f1. file đã là một số nhận dạng được sử dụng trong ngôn ngữ, bạn phải tránh nó.

Vâng. Bây giờ trận đối tượng này xấu tên được định nghĩa, các hướng dẫn fixed_doc = match.sub(r' ',text) thay thế tất cả các lần xuất hiện được tìm thấy bởi các regex trận đấu trong văn bản với sự thay thế r' '.
Lưu ý rằng nó hoàn toàn không cần thiết để viết r' ' thay vì chỉ ' ' vì hoàn toàn không có gì trong ' ' cần phải được thoát. Đó là một mốt của một số người lo lắng để viết chuỗi thô mỗi khi họ phải viết một chuỗi trong một vấn đề regex.

Bởi vì mô hình của nó <.+> trong đó chấm biểu tượng có nghĩa là "tham lam ăn mỗi nhân vật nằm giữa một <> trừ khi đó là một ký tự xuống dòng", những lần xuất hiện đánh bắt trong đoạn văn bằng trận đấu là mỗi dòng cho đến khi cuối cùng là > trong đó.
Vì tên unwanted không xuất hiện trong hướng dẫn này, nó là cùng một thao tác được thực hiện cho từng ký tự của văn bản, cái này sau cái kia. Đó là để nói: không có gì thú vị.
Để phân tích việc thực hiện chương trình, bạn nên đặt một số hướng dẫn in trong mã của mình, cho phép để hiểu điều gì xảy ra.Ví dụ: nếu bạn thực hiện print repr(fixed_doc), bạn sẽ thấy bản in lặp lại của điều này: ' \n \n \n '. Như tôi đã nói: không có gì thú vị cả.

Có thêm một mặc định trong mã của bạn: bạn mở tệp nhưng không đóng chúng. Nó là bắt buộc để đóng các tập tin, nếu không nó có thể xảy ra một số hiện tượng lạ, mà tôi personnally quan sát thấy trong một số mã của tôi trước khi tôi nhận ra nhu cầu này. Một số người giả vờ nó không phải là bắt buộc, nhưng nó sai.
Nhân tiện, cách tốt hơn để mở và đóng tệp là sử dụng câu lệnh with. Nó làm tất cả công việc mà không cần phải lo lắng.

.

Vì vậy, bây giờ tôi có thể đề nghị bạn một mã cho vấn đề đầu tiên của bạn:

import re 

def ripl(mat=None,li = []): 
    if mat==None: 
     li[:] = [] 
     return 
    if mat.group(1): 
     li.append(mat.span(2)) 
     return '' 
    elif mat.span() in li: 
     return '' 
    else: 
     return mat.group() 

r = re.compile('</[^>]+>' 
       '|' 
       '<([^>]+)>(?=.*?(</\\1>))', 
       re.DOTALL) 

text = '''<something @37> 
<name>George <wxc>Washington</name> 
<a23c>Joe </zazaza>Taylor</a23c> 
</something @37>''' 
print '1------------------------------------1' 
print text 
print '2------------------------------------2' 
ripl() 
print r.sub(ripl,text) 
print '3------------------------------------3' 

kết quả

1------------------------------------1 
<something @37> 
<name>George <wxc>Washington</name> 
<a23c>Joe </zazaza>Taylor</a23c> 
</something @37> 
2------------------------------------2 

George <wxc>Washington 
Joe </zazaza>Taylor 

3------------------------------------3 

Nguyên tắc là như sau:

Khi regex phát hiện một thẻ,
- nếu đó là thẻ kết thúc, thẻ khớp với - nếu đó là thẻ bắt đầu, thẻ đó sẽ chỉ khớp nếu có thẻ kết thúc tương ứng ở đâu đó hơn nữa trong văn bản
Đối với mỗi trận đấu, phương pháp sub() của regex r gọi hàm ripl() để thực hiện thay thế.
Nếu kết quả phù hợp với thẻ bắt đầu (cần phải tuân thủ một nơi nào đó trong văn bản bằng thẻ kết thúc tương ứng, bằng cách xây dựng regex), thì ripl() trả về ''.
Nếu kết hợp trùng với thẻ kết thúc, ripl() chỉ trả lại '' nếu thẻ kết thúc này trước đây trong văn bản được phát hiện là thẻ kết thúc tương ứng của thẻ bắt đầu trước đó. Điều này có thể thực hiện được bằng cách ghi lại trong danh sách li khoảng thời gian của mỗi thẻ kết thúc tương ứng mỗi khi thẻ bắt đầu được phát hiện và đối sánh.

Danh sách ghi li được định nghĩa là một đối số mặc định theo thứ tự mà nó luôn luôn cùng một danh sách được sử dụng tại mỗi cuộc gọi của hàm ripl() (xin vui lòng, hãy tham khảo functionning của đối số mặc định để undertsand, bởi vì nó tinh tế).
Kết quả của định nghĩa li là tham số nhận đối số mặc định, đối tượng danh sách li sẽ giữ lại tất cả các nhịp được ghi lại khi phân tích nhiều văn bản trong trường hợp một số văn bản sẽ được phân tích liên tiếp. Để tránh danh sách li để giữ lại các nhịp của các kết quả văn bản trong quá khứ, cần phải làm cho danh sách trống. Tôi đã viết hàm để tham số đầu tiên được xác định với đối số mặc định None: cho phép gọi ripl() mà không có đối số trước khi sử dụng bất kỳ tham số nào trong phương thức sub() của regex.
Sau đó, người ta phải nghĩ đến việc viết ripl() trước khi sử dụng.

.

Nếu bạn muốn loại bỏ các dòng mới của văn bản để có được kết quả chính xác mà bạn thấy trong câu hỏi của bạn, mã phải được sửa đổi để:

import re 

def ripl(mat=None,li = []): 
    if mat==None: 
     li[:] = [] 
     return 
    if mat.group(1): 
     return '' 
    elif mat.group(2): 
     li.append(mat.span(3)) 
     return '' 
    elif mat.span() in li: 
     return '' 
    else: 
     return mat.group() 


r = re.compile('(*\n *)' 
       '|' 
       '</[^>]+>' 
       '|' 
       '<([^>]+)>(?=.*?(</\\2>)) *', 
       re.DOTALL) 

text = '''<something @37> 
<name>George <wxc>Washington</name> 
<a23c>Joe </zazaza>Taylor</a23c> 
</something @37>''' 
print '1------------------------------------1' 
print text 
print '2------------------------------------2' 
ripl() 
print r.sub(ripl,text) 
print '3------------------------------------3' 

kết quả

1------------------------------------1 
<something @37> 
<name>George <wxc>Washington</name> 
<a23c>Joe </zazaza>Taylor</a23c> 
</something @37> 
2------------------------------------2 
George <wxc>WashingtonJoe </zazaza>Taylor 
3------------------------------------3 
+0

@Duboe Xin vui lòng, xem câu trả lời của tôi. Lưu ý rằng ký tự thay thế mà tôi đã sử dụng trong nó là '' '' '', không phải là một '' '' '' trống – eyquem

1

Bạn có thể sử dụng Beautiful Soup để làm điều này một cách dễ dàng:

from bs4 import BeautifulSoup 
file = open('f1.txt') 
fixed = open('fnew.txt','w') 

#now for some soup 

soup = BeautifulSoup(file) 

fixed.write(str(soup.get_text()).replace('\n',' ')) 

Đầu ra của dòng trên sẽ là:

George Washington Joe Taylor 

(làm việc Atleast này với mẫu mà bạn đã cho tôi)

Xin lỗi tôi không hiểu phần 2, chúc bạn may mắn!

+0

Đó là khá tốt đẹp mặc dù tôi không thể sử dụng phần mở rộng mà không được bao gồm:/nhưng thx tôi có thể sử dụng cho một số dự án trong tương lai :) – dustinboettcher

0

Đã tìm ra phần đầu tiên là thiếu '?'

match = re.compile('<.*?>') 

thực hiện thủ thuật.


Dù sao vẫn không chắc về câu hỏi thứ hai. :/

+0

Đó là một giải pháp quá đơn giản. Ví dụ với '' text = 'Atlantic <--- đây là một đại dương. << >> \ nBat <--- đây là một động vật * xóa nó * ''' kết quả của '' re.sub (' <.+?> ',' ', văn bản) '' là ''' Đại Tây Dương >> \ nBat < --- đây là một con vật * loại bỏ nó * '''. Đó là để tránh những trường hợp như vậy mà tôi đã viết mã trong câu trả lời của tôi – eyquem

0

Đối với phần 1, hãy thử đoạn mã bên dưới. Tuy nhiên xem xét sử dụng một thư viện như BeautifulSoup theo đề nghị của Moe Jan

import re 
import os 
def main(): 
    f = open('sample_file.txt') 
    fixed = open('fnew.txt','w') 



    #pattern = re.compile(r'(?P<start_tag>\<.+?\>)(?P<content>.*?)(?P<end_tag>\</.+?\>)') 
    pattern = re.compile(r'(?P<start><.+?>)(?P<content>.*?)(</.+?>)') 
    output_text = [] 
    for text in f: 
     match = pattern.match(text) 
     if match is not None: 
      output_text.append(match.group('content')) 

    fixed_content = ' '.join(output_text) 


    fixed.write(fixed_content) 
    f.close() 
    fixed.close() 

if __name__ == '__main__': 
    main() 

Về phần 2:

Tôi không hoàn toàn rõ ràng với những gì bạn đang yêu cầu - tuy nhiên tôi đoán là bạn muốn làm một cái gì đó như if re.sub(value) not in []. Tuy nhiên, lưu ý rằng bạn cần gọi re.compile chỉ một lần trước khi khởi tạo phiên bản Counter. Sẽ tốt hơn nếu bạn làm rõ phần thứ hai của câu hỏi.

Thực ra, tôi khuyên bạn nên sử dụng mô-đun tìm khác biệt được xây dựng trong Python để tìm sự khác biệt giữa hai tệp.Sử dụng cách này tốt hơn sử dụng thuật toán khác của riêng bạn, vì logic khác được kiểm tra và sử dụng rộng rãi và không dễ bị lỗi logic hoặc lập trình do sự hiện diện của các dòng mới, tab và ký tự dấu cách.