views:

76

answers:

4

Hi, guys,

I have a file as follows:

line 1: _____
   ...
# for AAA
#export CONFIG = AAA_defconfig

# for BBB, BbB, Bbb, BBb3
#export CONFIG = BBB_defconfig

# for CCC, CcC, Ccc, Ccc1
#export CONFIG = CCC_defconfig
   ...
other lines

I want manipulate the file, so that based on the given string, I could export the right "CONFIG", and comment the others. e.g. if I got "CcC", then the file would be manipulated as

line 1: _____
    ...
# for AAA
#export CONFIG = AAA_defconfig

# for BBB, BbB, Bbb, BBb3
#export CONFIG = BBB_defconfig

# for CCC, CcC, Ccc, Ccc1
export CONFIG = CCC_defconfig
    ...
other lines

what the good way to do it in python?

Thanks in advance!!

+1  A: 

Then why not make it as

line = 'xxxx'
CONFIG = default_deconfig

if line == 'AAA':
    CONFIG =  AAA_defconfig
elif line == 'CCC':
    CONFIG =  CCC_defconfig
...

unless this is not a python file and you want to manipulate it. It looks like that.

In that case create a config generator which will create a config file based on the line variable.

[Edit: Based on comments]

You might have to make some adjustments but this should work.

# Simple , crude solution

f = open('file1', 'r')
manipulated_lines = []
readFirstLine = False
config = ''
configComma = ''
uncommentLine = 0
for line in f:
    tokens = line.split()

    if uncommentLine == 1:
        # this is comment line
        if tokens[0] == '#export':
            manipulated_lines.append(line[1:])
            uncommentLine = uncommentLine + 1
            continue
    elif uncommentLine > 1:
        manipulated_lines.append(line)
        continue

    if not readFirstLine: 
        config = line.rstrip('\n')
        configComma = config + ','
        readFirstLine = True

    # Process additional lines 
    manipulated_lines.append(line)

    if len(tokens) > 0 and tokens[0] == '#':
        if tokens[1] == 'for':
            if config in tokens or configComma in tokens:
                uncommentLine = uncommentLine + 1
                continue

print manipulated_lines
f.close()
fw = open('file2', 'w')
fw.writelines(manipulated_lines)
fw.close()

Input: file1

CCC
# for AAA
#export CONFIG = AAA_defconfig

# for BBB, BbB, Bbb, BBb3
#export CONFIG = BBB_defconfig

# for CCC, CcC, Ccc, Ccc1
#export CONFIG = CCC_defconfig
   ...

Output: file2

CCC
# for AAA
#export CONFIG = AAA_defconfig

# for BBB, BbB, Bbb, BBb3
#export CONFIG = BBB_defconfig

# for CCC, CcC, Ccc, Ccc1
export CONFIG = CCC_defconfig
   ...
pyfunc
hi, pyfunc, the file to manipulate is not a py file at all, it is just an ordinary txt file and it is given, I could only modify it.
pepero
@pepero: I was confused on that. In that case the answer from nosklo should suffice. It is exactly what you want.
pyfunc
please see my comments on his solution. anyway, pyfunc, thank you for your input.
pepero
@pepero: Provided solution that should work and you can optimize it.
pyfunc
+1  A: 
def select_export(text, source, destination):
    uncomment_next = False
    for line in source:
        line = line.strip()
        if line.startswith('# for ') and text in set(t.strip() 
                for t in line[6:].split(',')):
            uncomment_next = True
        elif line.startswith('#') and uncomment_next:
            line = line[1:]
            uncomment_next = False
    destination.write(line + '\n')



with open('source') as f:
    with open('destination', 'w') as w:
        select_export('CcC', f, w)
nosklo
hi, nosklo, thank you for your input. However, your solution has following problems: 1) I need to find the 'CONFIG' line first, and then check if the previous line has 'text' or not. you solution assumes there is no other type of '# for text' used in the file. 2) most importantly, and also what I want to know most, is it possible to change the line without rewriting the whoe file in python? Thank you all the same!
pepero
+1  A: 

A little cleaner more readable approach IMO.

(And, yes, to modify one line in a file, you have to overwrite and rewrite the entire file.)

#!/usr/bin/env python2.7
import re

def find_and_modify(config_file, given_string):

    with open(config_file) as f:
        lines = f.readlines()

    given_string_re = re.compile(r'# for .*{}'.format(given_string))

    # line #'s that start with either "export" or "#export"
    export_line_numbers = []
    # the line # containing the given_string we're searching for
    uncomment_line_number = None

    for i,line in enumerate(lines):
        if re.match(r'#?export', line):
            export_line_numbers.append(i)
            prev_line = lines[i-1]
            if given_string_re.match(prev_line):
                uncomment_line_number = i

    for i in export_line_numbers:
        if i == uncomment_line_number:
            lines[i] = re.sub(r'^#*', '', lines[i])
        else:
            lines[i] = re.sub(r'^#*', '#', lines[i])

    with open(config_file, 'w') as f:
        f.writelines(lines)

find_and_modify('some_file', 'AAA')
find_and_modify('some_file', 'CcC')
ma3
+1  A: 

First create a generator function:

import re
def uncomment(seq, prev_pattern, curr_pattern):
    """Remove comment from any string in seq matching curr_pattern if the previous line matches prev_pattern"""
    prev = ""
    for curr in seq:
        if re.match(curr_pattern, curr) and re.match(prev_pattern, prev):
            yield curr[1:]
    else:
       yield curr
    prev = curr

Now test it:

>>> lines = ["leave this alone", "#fix next line", "#fix this line", "leave this alone"]
>>> print "\n".join(uncomment(lines, "^#fix next", "^#fix this"))
leave this alone
#fix next line
fix this line
leave this alone

Now use it to fix your file:

with open(input_filename, 'r') as f_in:
    with open(output_filename, 'w') as f_out:
        for line in uncomment(f_in, "^#for AAA", "^#export CONFIG"):
            f_out.write(line)
Robert Rossney