找到字符串并用某些东西替换下几行

时间:2014-02-28 15:01:54

标签: python regex

我正在编写一个Python脚本,要求提供文件和名称(例如“John”)。

该文件包含大量这样的行:

...
Name=John
Age=30
Pay=1000
Married=1
Name=Bob
Age=25
Pay=500
Married=0
Name=John
Age=56
Pay=3000
Married=1
...

我想打开此文件,询问用户名称,并替换与该名称匹配的所有条目的付款值。因此,例如,用户输入“John”,我想将所有“John”的Pay更改为5000,其他名称的Pay值不会改变。

到目前为止,我已打开文件并将所有内容连接成一个长字符串,以使事情变得更容易:

for line in file:
    file_string += line

起初,我正在考虑某种字符串替换,但是由于我会搜索“John”但我不想取代“John”,而是替换“John”,而不是Pay值。两行下来。

我开始使用正则表达式,并想出了类似的东西。

# non-greedy matching
re.findall("Name=(.*?)\nAge=(.*?)\nPay=(.*?)\n", file_string, re.S)

好吧,这样就会吐出这些分组的3元组列表,它似乎确实找到了一切。现在,做实际的替换...

我在StackOverflow上的另一个问题上读到,我可以设置分组的名称并稍后使用该分组......:

re.sub(r'Name=(.*?)\nAge=(.*?)\nPay=', r'5000', file_string, re.S)

我试过看看它是否会起作用并将所有名称替换为5000,但事实并非如此。如果它那么我可能会检查第一组,看它是否与用户输入的名称相匹配。

另一个问题是我在Python文档中读到re.sub仅替换最左边的事件。我想替换所有出现的事件。我该怎么做?

现在,如果有人能帮助我,我会有点失去这样做会很棒!

3 个答案:

答案 0 :(得分:2)

一次迭代4行。如果第一行包含“John”,则编辑后面两行的行。

data = """
Name=John
Age=30
Pay=1000
Married=1
Name=Bob
Age=25
Pay=500
Married=0
Name=John
Age=56
Pay=3000
Married=1
"""

lines = data.split() 
for i, value in enumerate(zip(*[iter(lines)]*4)):
    if 'John' in value[0]:
        lines[i*4 + 2] = "Pay=5000"

print '\n'.join(lines)

答案 1 :(得分:2)

我不认为正则表达式是解决此问题的最佳方法。我更喜欢更通用的解决方案其他答案取决于以下一项或多项:

  1. 一个人总有4个属性。
  2. 每个人都有相同的属性。
  3. 属性始终采用相同的顺序。
  4. 如果你的情况属实,那么正则表达式就可以了。

    我的解决方案更详细,但并不依赖于这些。它处理混合/缺失属性,混合顺序,并能够设置和获取任何属性值。您甚至可以延长它,并在需要时支持新的财产或人员插入。

    我的代码:

    # i omitted "data = your string" here
    
    def data_value(person_name, prop_name, new_value = None):
        global data
        start_person = data.find("Name=" + person_name + "\n")
        while start_person != -1:
            end_person = data.find("Name=", start_person + 1)
            start_value = data.find(prop_name + "=", start_person, end_person)        
            if start_value != -1:
                start_value += len(prop_name) + 1
                end_value = data.find("\n", start_value, end_person)
                if new_value == None:
                    return data[start_value:end_value]
                else:
                    data = data[:start_value] + str(new_value) + data[end_value:]                
            start_person = data.find("Name=" + person_name + "\n", end_person)
        return None
    
    print data_value("Mark", "Pay")    # Output: None (missing person)
    print data_value("Bob", "Weight")  # Output: None (missing property)
    print data_value("Bob", "Pay")     # Output: "500" (current value)
    data_value("Bob", "Pay", 1234)     # (change it)
    print data_value("Bob", "Pay")     # Output: "1234" (new value)
    
    data_value("John", "Pay", 555)     # (change it in both Johns)
    

答案 2 :(得分:1)

以下代码将满足您的需求:

import re

text = """
Name=John
Age=30
Pay=1000
Married=1
Name=Bob
Age=25
Pay=500
Married=0
Name=John
Age=56
Pay=3000
Married=1
"""

# the name you're looking for
name = "John"
# the new payment
pay = 500

print re.sub(r'Name={0}\nAge=(.+?)\nPay=(.+?)\n'.format(re.escape(name)), r'Name=\1\nAge=\2\nPay={0}\n'.format(pay), text)