我正在尝试通过split
,replace
和join
解析行数组。
我的最终目标是采用给定的代码段(对于所有重要问题,请使用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];
}
}
非常感谢!!
答案 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
来避免需要显式调用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
没有发生),因此我们将跳过没有任何显着事件的行({ {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)