代码之家  ›  专栏  ›  技术社区  ›  goodvibration

迭代行数组时,函数“replace”似乎不起作用

  •  0
  • goodvibration  · 技术社区  · 7 年前

    我正试图通过 split , replace join .

    我的最终目标是获取一段给定的代码(对于所有的代码来说都是稳定的),并在每个函数参数名前面加上一个下划线。

    以下是我的代码的最小化版本(仅限于手头问题的必要条件):

    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 回复  |  直到 7 年前
        1
  •  3
  •   Jean-François Fabre    7 年前

    问题是在你 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) 通过更强大的字替换方法,比如字边界替换regex,因为如果其他变量 开始 同样的字符串,它们也将被替换。

    >>> 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
    

    您的代码在生成的代码上工作,但很大程度上依赖于这样一个事实:参数后面紧跟着一些字符,而不是空格。手动编辑文件可能会破坏您的分析。

        2
  •  0
  •   C.Nivs    7 年前

    要读取文件,最好使用 with 避免 open close 需要明确调用:

    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 没有发生),所以我们将跳过没有任何显著事件的行。( FY型 )

    接下来,我们可以使用以下regex模式查找所有参数:

    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 看起来像:

    # ['var1', 'var2', 'var3', 'var4', 'var3[i]', 'var4[i]', 'var5']
    

    现在,借用上面@jean的回答,我不太担心复制品 var3 var4 因为我们已经在字符串上建立了这些边界:

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

    现在,你的文件看起来像

    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];
        }
    }