如何用Python正则表达式匹配MATLAB的函数语法?
我正在尝试找出我们内部库中所有MATLAB函数的输入和输出。我是第一次接触正则表达式(regex),正在尝试使用Python的re
库中的多行模式。
MATLAB函数的语法看起来像这样:
function output = func_name(input)
其中函数的定义可能会跨越多行。
我开始时用的模式是:
re.compile(r"^.*function (.*)=(.*)\([.\n]*\)$", re.M)
但我总是遇到不支持的模板操作符错误。任何指点都很感激!
编辑:
现在我有了:
pattern = re.compile(r"^\s*function (.*?)= [\w\n.]*?\(.*?\)", re.M|re.DOTALL)
这给出的匹配结果像这样:
function [fcst, spread] = ...
VolFcstMKT(R,...
mktVol,...
calibrate,...
spread_init,...
fcstdays,...
tsperyear)
if(calibrate)
if(nargin < 6)
tsperyear = 252;
end
templen = length(R)
我的问题是,为什么它会给出多余的行,而不是在第一个)
处停止?
3 个回答
那普通的Python字符串操作怎么样呢?这里只是一个例子。
for line in open("file"):
sline=line.strip()
if sline.startswith("function"):
lhs,rhs =sline.split("=")
out=lhs.replace("function ","")
if "[" in out and "]" in out:
out=out.replace("]","").replace("[","").split(",")
print out
m=rhs.find("(")
if m!=-1:
rhs=rhs[m:].replace(")","").replace("(","").split(",")
print rhs
输出示例
$ cat file
function [mean,stdev] = stat(x)
n = length(x);
mean = sum(x)/n;
stdev = sqrt(sum((x-mean).^2/n));
function mean = avg(x,n)
mean = sum(x)/n;
$ python python.py
['mean', 'stdev ']
[' statx']
mean
[' avgx', 'n']
当然,在Matlab中声明函数还有很多其他的情况,比如 function nothing
、function a = b
等等,所以这些检查就需要你自己添加了。
这里有一个正则表达式,可以用来匹配m文件开头的任何MATLAB函数声明:
^\s*function\s+((\[[\w\s,.]*\]|[\w]*)\s*=)?[\s.]*\w+(\([^)]*\))?
接下来,我会详细解释一下这个表达式的组成部分:
^\s* # Match 0 or more whitespace characters
# at the start
function # Match the word function
\s+ # Match 1 or more whitespace characters
( # Start grouping 1
( # Start grouping 2
\[ # Match opening bracket
[\w\s,.]* # Match 0 or more letters, numbers,
# whitespace, underscores, commas,
# or periods...
\] # Match closing bracket
|[\w]* # ... or match 0 or more letters,
# numbers, or underscores
) # End grouping 2
\s* # Match 0 or more whitespace characters
= # Match an equal sign
)? # End grouping 1; Match it 0 or 1 times
[\s.]* # Match 0 or more whitespace characters
# or periods
\w+ # Match 1 or more letters, numbers, or
# underscores
( # Start grouping 3
\( # Match opening parenthesis
[^)]* # Match 0 or more characters that
# aren't a closing parenthesis
\) # Match closing parenthesis
)? # End grouping 3; Match it 0 or 1 times
无论你是用正则表达式还是基本的字符串操作,都要记住MATLAB中函数声明的不同形式。一般来说,它的基本格式是:
function [out1,out2,...] = func_name(in1,in2,...)
具体来说,你可能会看到以下几种形式:
function func_name %# No inputs or outputs
function func_name(in1) %# 1 input
function func_name(in1,in2) %# 2 inputs
function out1 = func_name %# 1 output
function [out1] = func_name %# Also 1 output
function [out1,out2] = func_name %# 2 outputs
...
在很多地方,比如等号后面或者参数列表中,你还可以使用换行符(...
):
function out1 = ...
func_name(in1,...
in2,...
in3)
你可能还需要考虑一些因素,比如可变输入参数列表和被忽略的输入参数:
function func_name(varargin) %# Any number of inputs possible
function func_name(in1,~,in3) %# Second of three inputs is ignored
你遇到的这个奇怪的内部错误,可能是因为你在调用 re.compile
时,把 re.T
作为第二个参数传入,而不是 re.M
。其实 re.template
是一个目前还没有文档说明的选项,主要是用来处理模板的正则表达式,而模板的正则表达式不支持重复或回溯。你能在调用 re.compile
之前,先用 print re.M
打印一下它的值吗?
一旦这个问题解决了,我们可以讨论你想要的正则表达式的细节(简单来说,如果 input
部分可以包含括号,那就没办法了;否则,使用 re.DOTALL
和对你的模式进行一些重写应该会有帮助)——不过,先解决这个奇怪的内部错误更重要。
编辑:在诊断出这个错误后(根据下面评论的内容),我们可以继续讨论提问者当前的问题:re.DOTALL|re.MULTINE
,再加上模式末尾的 '$',以及到处都是贪婪匹配(使用 .*
,而不是 .*?
进行非贪婪匹配),这些组合在一起确保如果正则表达式匹配的话,它会尽可能广泛地匹配……这正是这个组合所要求的。最好是另开一个问题,给出具体的例子:输入是什么,匹配到了什么,你希望正则表达式匹配到什么等等。