簡體   English   中英

Python:re.compile 和 re.sub

[英]Python: re.compile and re.sub

問題第 1 部分

我得到了這個文件 f1:

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

我想重新編譯它,它看起來像這樣 f1:(帶空格)

George Washington Joe Taylor

我試過這段代碼,但它有點刪除了所有內容:

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)

我的猜測是 re.compile 行,但我不太確定如何處理它。 我不應該使用 3rd 方擴展。 有任何想法嗎?


問題第 2 部分

我有一個關於比較 2 個文件的不同問題,我從 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))

是否可以在“if value not in []”部分中實現 re.compile 和 re.sub?

我將解釋您的代碼會發生什么:

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)

指令text = file.read()創建一個名為型的對象文本 text
請注意,我使用粗體字符文本來表示OBJECT,並使用text來表示此對象的名稱== IDENTIFIER。
作為for unwanted in text:的指令的結果for unwanted in text:unwanted的標識符被連續地分配給文本對象引用的每個字符。

此外, re.compile('<.*>')創建一個RegexObject類型的對象(我個人稱之為編譯)正則表達式或簡單的正則表達式<.*>只是正則表達式模式 )。
您將此編譯的正則表達式對象分配給標識符match :這是一個非常糟糕的做法,因為match已經是正則表達式對象的方法的名稱,特別是您創建的方法的名稱,因此您可以編寫match.match而不用錯誤。
match也是re模塊的函數名稱。
使用此名稱滿足您的特殊需求非常令人困惑。 你必須避免這種情況。

使用file作為文件f1的文件處理程序的名稱存在同樣的缺陷。 file已經是語言中使用的標識符,你必須避免使用它。

好。 現在定義了這個命名錯誤的匹配對象,指令fixed_doc = match.sub(r' ',text)將替換fixed_doc = match.sub(r' ',text)所有正則表達式匹配文本替換為r' '
請注意,這是完全多余的寫r' '而不是僅僅' '因為絕對沒有什么在' '需要進行轉義。 每當他們必須在正則表達式問題中編寫字符串時,一些焦慮的人都會寫一些原始字符串。

因為它的模式<.+> ,其中點符號的意思是“貪婪地吃掉位於<和a >之間的每個字符,除非它是換行符”,在匹配的文本中捕獲的出現的每一行都是直到最后一個>在里面。
由於此指令中不顯示unwanted的名稱,因此對於文本的每個字符,它是一個接一個地執行的操作。 也就是說:沒什么好玩的。
要分析程序的執行,您應該在代碼中添加一些打印指令,以便了解發生的情況。 例如,如果你print repr(fixed_doc) ,你會看到重復打印: ' \\n \\n \\n ' 正如我所說:沒有什么有趣的。

您的代碼中還有一個默認值:您打開文件,但不關閉它們。 關閉文件是強制性的,否則它可能會發生一些奇怪的現象,在我意識到這種需要之前,我個人在我的一些代碼中觀察到了這些現象。 有些人假裝它不是強制性的,但它是假的。
順便說一下,打開和關閉文件的更好方式是使用with語句。 它可以完成所有工作而無需擔心。

那么,現在我可以為您提出第一個問題的代碼:

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'

結果

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

原則如下:

當正則表達式檢測到標簽時,
- 如果它是一個結束標記,它匹配 - 如果它是一個開始標記,它只有在文本中的某個地方有相應的結束標記時才匹配
對於每個匹配,正則表達式r的方法sub()調用函數ripl()來執行替換。
如果匹配是一個開始標記(必須在文本中的某個地方跟隨其相應的結束標記,通過構造正則表達式),則ripl()返回''
如果匹配是結束標記,則ripl()僅在檢測到文本中的此結束標記與先前開始標記的對應結束標記時才返回'' 這是通過在一個列表的每個相應的結束標記的跨度每次檢測開始標記時間和匹配的跨度記錄完成的可能。

記錄列表li被定義為默認參數,以便它始終與函數ripl()每次調用時使用的列表相同(請參考ripl()的默認參數的函數,因為它是微妙的)。
由於將li定義為接收默認參數的參數,列表對象li將保留在分析若干文本時記錄的所有跨度,以防連續分析若干文本。 為了避免列表li保留過去文本匹配的跨度,有必要使列表為空。 我編寫了函數,以便第一個參數定義為默認參數None :允許在正則表達式的sub()方法中使用它之前調用ripl()而不使用參數。
然后,必須考慮在使用它之前編寫ripl()

如果要刪除文本的換行符以獲得您在問題中顯示的精確結果,則必須將代碼修改為:

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'

結果

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

您可以使用Beautiful Soup輕松完成此操作:

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',' '))

上述行的輸出將是:

George Washington Joe Taylor

(至少這適用於你給我的樣本)

對不起,我不明白第2部分,祝你好運!

想出第一部分就是缺少'?'

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

訣竅。


無論如何仍然不確定第二個問題。 :/

對於第1部分,請嘗試以下代碼段。 但是考慮使用像Moe Jan建議的像beautifulsoup這樣的庫

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()

第2部分

我並不完全清楚你所問的是什么 - 但是我的猜測是你想要做的事情, if re.sub(value) not in [] 但是,請注意,在初始化Counter實例之前,只需要調用re.compile一次。 如果你澄清問題的第二部分會更好。

實際上,我建議您使用內置的Python diff模塊來查找兩個文件之間的差異。 使用這種方法比使用自己的diff算法更好,因為diff邏輯經過了很好的測試和廣泛使用,並且不容易受到虛假換行符,制表符和空格字符的影響而導致的邏輯或編程錯誤。

不需要重新編譯

進口重新

enter code here clean_string = ''

使用 open('f1.txt') 作為 f1:
對於 f1 中的行:
match = re.search('.+>(.+)<.+', line)
如果匹配:
clean_string += (match.group(1))
clean_string += ' '

打印(clean_string)#'喬治華盛頓喬泰勒'

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM