迭代行数组时,功能“替换”似乎不起作用

时间:2019-02-06 19:12:32

标签: python parsing join replace split

我正在尝试通过splitreplacejoin解析行数组。

我的最终目标是采用给定的代码段(对于所有重要问题,请使用Solidity编码),并在每个函数参数名称前加下划线。

这是我的代码的最小化版本(仅对当前问题有必要):

def checkLine(line):
    return any([line.startswith('    '+word) for word in ['function','constructor','event']])

def checkWord(word):
    return any([word.startswith(x) for x in 'abcdefghijklmnopqrstuvwxyz']) and any([word.endswith(x) for x in ',);'])

def parseFile(fileName):
    fileDesc = open(fileName, 'r')
    lines = fileDesc.read().split('\n')
    fileDesc.close()

    for n in range(len(lines)):
        if checkLine(lines[n]):
            for word in lines[n].split(' '):
                if checkWord(word):
                    lines[n] = lines[n].replace(word,'_'+word)
                    if lines[n].endswith('{'):
                        m = n+1
                        while not lines[m].endswith('}'):
                            lines[m] = lines[m].replace(word,'_'+word)
                            m += 1

    fileDesc = open(fileName, 'w')
    fileDesc.write('\n'.join(lines))
    fileDesc.close()

这是我几个小时一直在打头的问题:

lines[n] = lines[n].replace(word,'_'+word)行做得很好。

但是lines[m] = lines[m].replace(word,'_'+word)行没有任何作用。

所以我能够在函数头中更改参数名称,但不能在函数主体中更改

有人可以启发我吗?

这是一个示例输入文件:

pragma solidity 0.4.25;

import "./interfaces/IMyContract.sol";

/**
 * @title My Contract.
 */
contract MyContract is IMyContract {
    string public constant version = "1.0.0";

    mapping(bytes32 => address) private something;

    event Event(bytes32 indexed var1, address indexed var2);

    /**
     * @dev ...
     * @param var3 ...
     * @param var4 ...
     */
    constructor(bytes32[] memory var3, address[] var4) public {
        uint256 length = var3.length;
        require(length == var4.length);
        for (uint256 i = 0; i < length; i++) {
            require(uint256(something[var3[i]]) == 0);
            something[var3[i]] = var4[i];
            emit Event(var3[i], var4[i]);
        }
    }

    /**
     * @dev ...
     * @param var5 ...
     */
    function get(bytes32 var5) external view returns (address) {
        return something[var5];
    }
}

非常感谢!!

2 个答案:

答案 0 :(得分:3)

问题是,在进行checkWord测试之后,您需要去除尾随的括号,冒号等...否则替换对于其余令牌无效。

使用rstrip删除这些字符,然后替换就可以了。

    for word in lines[n].split(' '):
        if checkWord(word):
            word = word.rstrip(',);')

示例输出:

constructor(bytes32[] memory _var3, address[] _var4) public {
    uint256 length = _var3.length;
    require(length == _var4.length);
    for (uint256 i = 0; i < length; i++) {
        require(uint256(something[_var3[i]]) == 0);

还可以通过更强大的单词替换方法(如单词边界替换正则表达式)来更改lines[m].replace(word,"_"+word),因为如果其他变量以相同的字符串开始,它们也会被替换。

>>> s = "hello var4 this is var41"
>>> s.replace("var4",'_var4')
'hello _var4 this is _var41'   # wrong!
import re
>>> re.sub(r"\b({})\b".format("var4"),r"_\1",s)
'hello _var4 this is var41'  # correct

您的代码在生成的代码上有效,但是在很大程度上取决于以下事实:参数后面紧跟一些字符,而不是空格。手动编辑文件可能会破坏您的解析。

答案 1 :(得分:0)

要读取文件,最好使用with来避免需要显式调用openclose

with open(myfile) as fh:
    lines = fh.readlines()

您可以省去'r'标志,因为文件将在读取模式下自动打开。

从这里,您可以使用for这样的循环来查看事件类型是否在一行中:

f_types = ['Event', 'constructor', 'function']

for line in lines:
    for f in f_types:
        if f in line:
            break
    else:
         continue

这里的else正在检查是否已结束f_types上的迭代(break没有发生),因此我们将跳过没有任何显着事件的行({ {1}})

接下来,我们可以使用以下正则表达式模式查找所有参数:

f_types

现在要存储所有内容,整个脚本将变为:

res = re.findall('\((.*?)\)', line)
# for the line constructor(bytes32[] memory var3, address[] var4)
# this returns ['bytes32[] memory var3, address[] var4']

# Now we want to split the line on commas to give each declaration and
# grab the last statement because we don't care about anything but the name
args = [x.split()[-1] for x in res[0].split(',')]

运行该命令后,f_types = ['Event', 'constructor', 'function'] allargs = [] # to store all of our replace calls at the end with open(myfile) as fh: lines = fh.readlines() for line in lines: for f in f_types: if f in line: break else: continue in_parens = re.findall('\w+\((.*?)\)', line)[0] args = [x.split()[-1] for x in in_parens.split(',') allargs.extend(args) 将如下所示:

allargs

现在,借鉴@Jean的回答,我不太担心重复的# ['var1', 'var2', 'var3', 'var4', 'var3[i]', 'var4[i]', 'var5'] var3,因为我们已经在字符串上建立了这些边界:

var4

现在,您的文件看起来像

whole_file = '\n'.join(lines)

for arg in allargs:
    whole_file = re.sub(r"\b(%s)\b" % arg, r'_\1', whole_file)