簡體   English   中英

如何在python中使用正則表達式替換模式?

[英]How to replace a pattern using regex in python?

我有一個如下所示的數據集:

Male    Name=Tony;  
Female  Name=Alice.1; 
Female  Name=Alice.2;
Male    Name=Ben; 
Male    Name=Shankar; 
Male    Name=Bala; 
Female  Name=Nina; 
###
Female  Name=Alex.1; 
Female  Name=Alex.2;
Male    Name=James; 
Male    Name=Graham; 
Female  Name=Smith;  
###
Female  Name=Xing;
Female  Name=Flora;
Male    Name=Steve.1;
Male    Name=Steve.2; 
Female  Name=Zac;  
###

我想更改列表,所以它看起來像這樣:

Male    Name=Class_1;
Female  Name=Class_1.1;
Female  Name=Class_1.2;
Male    Name=Class_1;
Male    Name=Class_1;
Male    Name=Class_1; 
Female  Name=Class_1;
###
Female  Name=Class_2.1; 
Female  Name=Class_2.2; 
Male    Name=Class_2; 
Male    Name=Class_2; 
Female  Name=Class_2;  
###
Female  Name=Class_3; 
Female  Name=Class_3; 
Male    Name=Class_3.1; 
Male    Name=Class_3.2; 
Female  Name=Class_3;
###

每個名稱都必須更改為它們所屬的類。 我注意到在數據集中,列表中的每個新類都用'###'表示。 所以我可以通過'###'將數據集拆分成塊,並計算###的實例。 然后使用正則表達式查找名稱,並將其替換為###的計數。

我的代碼看起來像這樣:

blocks = [b.strip() for b in open('/file', 'r').readlines()]
pattern = r'Name=(.*?)[;/]'
prefix = 'Class_'
triple_hash_count = 1

for line in blocks:
    match = re.findall(pattern, line)
    print match

for line in blocks:
    if line == '###':
        triple_hash_count += 1
        print line 
    else: 
        print(line.replace(match, prefix + str(triple_hash_count))) 

這似乎不起作用 - 沒有替換。

運行您提供的代碼時,我得到以下回溯輸出:

print(line.replace(match, prefix + str(triple_hash_count))) 
TypeError: Can't convert 'list' object to str implicitly

發生錯誤是因為type(match)評估為列表。 當我在PDB中檢查此列表時,它是一個空列表。 這是因為match已超出范圍,有兩個for循環。 所以讓我們把它們結合起來:

for line in blocks:
    match = re.findall(pattern, line)
    print(match)

    if line == '###':
        triple_hash_count += 1
        print(line) 
    else: 
        print(line.replace(match, prefix + str(triple_hash_count)))

現在你在match獲得內容,但仍然存在一個問題: re.findall的返回類型是一個字符串列表。 str.replace(...)期望單個字符串作為其第一個參數。

你可以作弊,並改變要print(line.replace(match[0], prefix + str(triple_hash_count)))的違規行print(line.replace(match[0], prefix + str(triple_hash_count))) - 但這假設您確定要找到正則表達式匹配每一行都不是### 一種更有彈性的方法是在嘗試調用str.replace()之前檢查是否有匹配。

最終代碼如下所示:

for line in blocks:
    match = re.findall(pattern, line)
    print(match)

    if line == '###':
        triple_hash_count += 1
        print(line) 
    else:
        if match: 
            print(line.replace(match[0], prefix + str(triple_hash_count)))
        else:
            print(line)

還有兩件事:

  1. 在第11行,您誤認為變量名稱。 它是triple_hash_count ,而不是hash_count
  2. 此代碼實際上不會更改作為第1行輸入提供的文本文件。您需要將line.replace(match, prefix + str(triple_hash_count))的結果寫回文件,而不僅僅是打印它。

問題源於使用第二個循環(以及錯誤命名的變量)。 這會奏效。

import re

blocks = [b.strip() for b in open('/file', 'r').readlines()]
pattern = r'Name=([^\.\d;]*)'
prefix = 'Class_'
triple_hash_count = 1

for line in blocks:

    if line == '###':
        triple_hash_count += 1
        print line     
    else:
        match = re.findall(pattern, line)
        print line.replace(match[0], prefix + str(triple_hash_count)) 

雖然你已經有了答案,但你可以用幾行來表達正常的表達式(它甚至可以是單行,但這不是很易讀):

import re
hashrx = re.compile(r'^###$', re.MULTILINE)
namerx = re.compile(r'Name=\w+(\.\d+)?;')

new_string = '###'.join([namerx.sub(r"Name=Class_{}\1".format(idx + 1), part) 
                for idx,part in enumerate(hashrx.split(string))])
print(new_string)

它能做什么:

  1. 首先,它在一行中查找### ,並且在MULTILINE模式下使用錨點^$
  2. 其次,它在Name之后查找可能的數字,將其捕獲到組1中(但是由於並非所有名稱都具有可選項,因此可以選擇)。
  3. 第三,它通過###拆分你的字符串並用enumerate()迭代它,因此有一個計數器用於插入數字。
  4. 最后,它再次通過###加入結果列表。

作為一個單行(雖然不可取):

new_string = '###'.join(
                [re.sub(r'Name=\w+(\.\d+)?;', r"Name=Class_{}\1".format(idx + 1), part) 
                for idx, part in enumerate(re.split(r'^###$', string, flags=re.MULTILINE))])

演示

一個演示說了超過幾千個單詞。

暫無
暫無

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

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