简体   繁体   中英

How to replace words/digits in a file

I'm trying to replace the global IP inside a file with a private one and create a mapping of them, so i can revert it back even if part of the new string is different. I'm stuck at the point of replace the global IP with the bogus one and write it to a file.

Starting file example:

ip route 192.168.1.0 255.255.0.0 10.10.10.2
ip route 192.168.1.0 255.255.0.0 1.1.1.2
ip route 1.1.1.1 255.255.0.0 1.1.1.3
interface FastEthernet1
ip address 1.1.1.1
duplex auto
speed auto

Wanted end result, some wording may change before revert back:

ip route ipv4 192.168.1.0 255.255.0.0 10.10.10.2
ip route ipv4 192.168.1.0 255.255.0.0 10.1.1.11
ip route ipv4 10.1.1.10 255.255.0.0 10.1.1.12
interface FastEthernet1
ip address 10.1.1.10
duplex auto
speed auto

The mapping I though is a dictionary like this:

mapping = {
    '1.1.1.2': "10.1.1.10", 
    '1.1.1.1': "10.1.1.10", 
    '1.1.1.3': "10.1.1.30
    }

I came out with this script until now, but it not doing what I want:

import re
import ipaddress


def load_file(file) -> str:
    with open(file, 'r') as f:
        return f.read()


def find_ips(config) -> set:
    ip_regex = '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
    match = set(re.findall(ip_regex, config))
    return match


def mapping_ip(ips) -> dict:
    counter = 0
    ip_table = {}
    for ip in ips:
        ip4_type = ipaddress.IPv4Address(ip)

        if ip4_type.is_global:
            counter += 1
            private = ipaddress.IPv4Address('10.1.1.10') + counter
            ip_table.update({
                ip: str(private),
                })
    return ip_table


def replace(mapping, s_file, d_file):
    with open(s_file, 'r') as reader, open(d_file, 'w') as writer:
        for line in reader:
            for orig, temp in mapping.items():
                if orig in line:
                    x = line.replace(orig, temp)
                    writer.write(x)

Any suggestion on how should I do the replace funcion? Only the IP can be change, the rest of the string need to stay as it's(revert back process).

You can simply use string replace on the lines of your source file:

Create source file:

t = """ip route 192.168.1.0 255.255.0.0 10.10.10.2
ip route 192.168.1.0 255.255.0.0 1.1.1.2
ip route 1.1.1.1 255.255.0.0 1.1.1.3
interface FastEthernet1
ip address 1.1.1.1
duplex auto
speed auto"""

with open("t.txt","w") as f: 
    f.write(t)

Replace stuff and write to "mod.txt" :

mapping = {
    '1.1.1.2': "10.1.1.10", 
    '1.1.1.1': "10.1.1.10", 
    '1.1.1.3': "10.1.1.30"
    }

with open("mod.txt","w") as m, open("t.txt") as data:
    for line in data:
        for key,replacewith in mapping.items():
            line = line.replace(key,replacewith)
        m.write(line)

with open("mod.txt") as f:
    print(f.read()) 

Output:

ip route 192.168.1.0 255.255.0.0 10.10.10.2
ip route 192.168.1.0 255.255.0.0 10.1.1.10
ip route 10.1.1.10 255.255.0.0 10.1.1.30
interface FastEthernet1
ip address 10.1.1.10
duplex auto
speed auto

This will try to replace each line m times (m == len(mapping)) and is not very speedy due to creating lots of intermediate strings (if something got replaced) - it is more a hacky solution to your problem.

You could harness re.sub in this case, following way:

import re
txt = 'ip route 192.168.1.0 255.255.0.0 10.10.10.2\nip route 192.168.1.0 255.255.0.0 1.1.1.2\nip route 1.1.1.1 255.255.0.0 1.1.1.3\ninterface FastEthernet1\nip address 1.1.1.1\nduplex auto\nspeed auto'
out = re.sub(r'1\.1\.1\.([1-3])','10.1.1.\g<1>0',txt)
print(out)

Output:

ip route 192.168.1.0 255.255.0.0 10.10.10.2
ip route 192.168.1.0 255.255.0.0 10.1.1.20
ip route 10.1.1.10 255.255.0.0 10.1.1.30
interface FastEthernet1
ip address 10.1.1.10
duplex auto
speed auto

For simplicity I hardcoded txt , most important line is that of re.sub :

out = re.sub(r'1\.1\.1\.([1-3])','10.1.1.\g<1>0',txt)

It replaces substrings of txt which match first argument with second argument, first argument contain one group ( [1-3] ) which is later referenced in second argument ( \\g<1> ) thus it in fact of executing following relacement:

1.1.1.1 to 10.1.1.10

1.1.1.2 to 10.1.1.20

1.1.1.3 to 10.1.1.30

However keep in mind that re.sub is working in single-pass fashion, unlike repeating usage of .replace method of str .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM