用指定的替换字符串替换文件中的单词并处理缩进级别

Replace words in a file with specified replacement string and handle indent level

所以我有一个练习。我必须编写一个 python 脚本来查找实际文件夹中扩展名为“.prog”的所有文件。 (程序的这一部分已经可以运行)。这个 prog 文件看起来像这样:

import sys

n = int(sys.argv[1]) ;print "Start of the program!"

LOOP i in range(1,n) [[print "The number:";print i]]

DECISION n < 5 [[print n ;print "smaller then 5"]]

输出应该是这样的:

import sys  

n = int(sys.argv[1]) 
print "Start of the program!"

for i in range(1,n) :
    print "The number:"
    print i

if n < 5 :
    print n 
    print "smaller then 5"

所以我必须将 LOOP 替换为 for,将 DECISION 替换为 if。它可以是“;”之前的 space,但不能在它之后。 '[[**]]' 始终包含 python 语句。 在 for 循环和 if 语句之后,命令总是必须在四个 space 之后开始。 这是我的代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def find():
import glob, os
os.chdir(os.getcwd())
for file in glob.glob("*.prog"):
    ProgToPy(file)


def  ProgToPy(f):
outname = f.replace("prog","py")
replacements = {'LOOP':'for',  'DECISION':'if', ' ;':'\n', ';':'\n    ', ' [[':' :\n    ', ']]':''}
with open(f) as infile, open(outname, 'w') as outfile:
    for line in infile:
        for src, target in replacements.iteritems():
            line = line.replace(src, target)
        outfile.write(line)

find()

问题在于我的输出如下所示:

import sys

n = int(sys.argv[1])
print "Start of the program!"

for i in range(1,n) :
    print "The number:"
    print i

if n < 5 :
    print n
print "smaller then 5"

如果我在替换中加入这样的内容 ' ;':'\n '。第一个打印将在四个 space 之后立即开始。然后创建的 .py 文件无法正常工作。

您可以使用正则表达式来解决您的问题。

import re
import glob, os

pattern = r'(.*)\[\[(.*)\]\]'
regex = re.compile(pattern)

def ProgToPy(f):
    outname = f.replace("prog","py")    
    replacements = {'LOOP':'for',  'DECISION':'if', ';': '\n\t'}

    with open(f) as infile, open(outname, 'w') as outfile:
        for line in infile:
            m = regex.match(line)

            if m:
                line = ''
                for matched_part in m.groups():
                    line += matched_part + '\n\t'

            for src, target in replacements.iteritems():
                line = line.replace(src, target)

            outfile.write(line)

os.chdir(os.getcwd())
for file in glob.glob("*.prog"):
    ProgToPy(file)

由于分号根据其位置的不同而有所不同,因此您基本上应该为每个状态编写单独的函数。 [[...]] 表示 Python 中的块作用域,所以我们称这些状态为 normal stateblock state

为了控制状态,我们将使用布尔变量 in_block 并使用正则表达式来确定其值。

这里,我把所有的替换任务都放在了一个replaceTokens函数中。

def replaceTokens(statement, in_block=False):
    if in_block:
        statement = statement.replace(SEMI, NEWLINE+TABSPACE)
        statement = statement.replace(OPEN_BRACKETS, COLON+NEWLINE+TABSPACE)
    else:
        statement = statement.replace(SEMI, NEWLINE)
        statement = statement.replace(OPEN_BRACKETS, COLON+NEWLINE)

    statement = statement.replace(CLOSE_BRACKETS, NEWLINE)

    statement = statement.replace(LOOP, FOR)
    statement = statement.replace(DECISION, IF)

    return statement

上面的代码看起来很乏味,但如果你愿意,你可以轻松地为此编写一个 for 循环。这里重要的一点是我使用的是布尔变量 in_block。这使您可以根据双括号的存在来决定是否在换行符后跟一个制表符。

要在块范围内查找语句,我使用正则表达式:

def progToPy(f):
    outname = f.replace("prog","py")
    rf = open(f, "r")
    text = rf.read()

    rf.close()

    block_regex = re.compile(r'\[\[.*\]\]')
    mo = block_regex.findall(text)

    for match in mo:
        statement = blockScope(match)
        text = text.replace(match, statement)

    text = replaceTokens(text)
    print(text)

blockScope函数仅用in_block=True替换块范围内的语句,然后先替换那些部分。然后,当我们对整个文档调用 replaceTokens 时,块范围内的那些已经被替换,因此不会受到第二次调用的影响。

def blockScope(block):
    statement = replaceTokens(block, in_block=True)
    return statement