用于查找包含字符串的方法名称的正则表达式
Regex for finding the name of a method containing a string
我有一个包含大约 100 个导出方法的 Node 模块文件,它看起来像这样:
exports.methodOne = async user_id => {
// other method contents
};
exports.methodTwo = async user_id => {
// other method contents
fooMethod();
};
exports.methodThree = async user_id => {
// other method contents
fooMethod();
};
目标:我想做的是弄清楚如何获取包含对 fooMethod
和 [=39 的调用的任何方法的名称=] 正确的方法名称:methodTwo 和 methodThree。我写了一个正则表达式 kinda close:
exports\.(\w+).*(\n.*?){1,}fooMethod
问题:不过,使用上面的示例代码,它会有效地匹配 methodOne 和 methodThree,因为它会找到 export
的第一个实例,然后是第一个实例fooMethod
并从那里继续。 Here's a regex101 example.
我想我可以使用先行或后行,但我对正则表达式的这些部分没有什么经验,所以任何指导将不胜感激!
编辑:事实证明正则表达式不适合此类任务。 @ctcherry 建议使用解析器,并将其用作跳板,我能够了解抽象语法树 (AST) 和 recast tool which lets you traverse the tree after using various tools (acorn 以及其他)将您的代码解析为树形式。
有了这些工具,我成功地构建了一个脚本来解析和遍历我的节点应用程序的文件,并且能够按预期找到包含 fooMethod
的所有方法。
假设所有方法的主体都包含在 {
和 }
中,我会采用这样的方法来获得最终的正则表达式:
- 首先,找到一个正则表达式来获取各个方法。这可以使用这个正则表达式来完成:
exports\.(\w+)(\s|.)*?\{(\s|.)*?\}
- 接下来,我们感兴趣的是那些在关闭之前里面有
fooMethod
的方法。因此,按此顺序查找 }
或 fooMethod.*}
。因此,让我们将搜索 fooMethod
的组命名为 FOO
,并将调用它的方法的名称命名为 METH
。当我们迭代匹配时,如果组 FOO
出现在匹配中,我们将使用相应的 METH
组,否则我们将拒绝它。
exports\.(?<METH>\w+)(\s|.)*?\{(\s|.)*?(\}|(?<FOO>fooMethod)(\s|.)*?\})
解释:
exports\.(?<METH>\w+)
: 直到方法名(你已经覆盖了这个)
(\s|.)*?\{(\s|.)*?
:{
之前和之后的一些代码,非贪心,以便后面的组优先
(\}|(?<FOO>fooMethod)(\s|.)*?\})
:这有两部分:
\}
:匹配方法结束分隔符,或
(?<FOO>fooMethod)(\s|.)*?\})
:调用 fooMethod
后跟可选代码和方法关闭分隔符。
这里有一个 JavaScript 代码来演示这个:
let p = /exports\.(?<METH>\w+)(\s|.)*?\{(\s|.)*?(\}|(?<FOO>fooMethod)(\s|.)*?\})/g
let input = `exports.methodOne = async user_id => {
// other method contents
};
exports.methodTwo = async user_id => {
// other method contents
fooMethod();
};
exports.methodThree = async user_id => {
// other method contents
fooMethod();
};';`
let match = p.exec( input );
while( match !== null) {
if( match.groups.FOO !== undefined ) console.log( match.groups.METH );
match = p.exec( input )
}
此正则表达式(仅)匹配包含对 fooMethod();
的调用的方法名称
(?<=exports\.)\w+(?=[^{]+\{[^}]+fooMethod\(\)[^}]+};)
参见live demo。
正则表达式并不是解决这个问题所有部分的最佳工具,理想情况下我们可以依赖更高级别的东西,一个解析器。
一种方法是让 javascript 在加载和执行期间自行解析。如果您的节点模块不包含任何可自行执行的内容(或至少不包含任何与以下内容冲突的内容),您可以将其放在模块的底部,然后 运行 使用 node mod.js
.
console.log(Object.keys(exports).filter(fn => exports[fn].toString().includes("fooMethod(")));
(在下面的评论中显示以上是不可能的。)
另一种选择是使用像 https://github.com/acornjs/acorn 这样的库(还有其他选项)来编写一些其他 javascript 来解析您的原始目标 javascript,那么您将拥有您可以使用树结构来执行匹配,并最终 return 您之后的函数名称。我不是该库的专家,所以很遗憾我没有适合您的示例代码。
我有一个包含大约 100 个导出方法的 Node 模块文件,它看起来像这样:
exports.methodOne = async user_id => {
// other method contents
};
exports.methodTwo = async user_id => {
// other method contents
fooMethod();
};
exports.methodThree = async user_id => {
// other method contents
fooMethod();
};
目标:我想做的是弄清楚如何获取包含对 fooMethod
和 [=39 的调用的任何方法的名称=] 正确的方法名称:methodTwo 和 methodThree。我写了一个正则表达式 kinda close:
exports\.(\w+).*(\n.*?){1,}fooMethod
问题:不过,使用上面的示例代码,它会有效地匹配 methodOne 和 methodThree,因为它会找到 export
的第一个实例,然后是第一个实例fooMethod
并从那里继续。 Here's a regex101 example.
我想我可以使用先行或后行,但我对正则表达式的这些部分没有什么经验,所以任何指导将不胜感激!
编辑:事实证明正则表达式不适合此类任务。 @ctcherry 建议使用解析器,并将其用作跳板,我能够了解抽象语法树 (AST) 和 recast tool which lets you traverse the tree after using various tools (acorn 以及其他)将您的代码解析为树形式。
有了这些工具,我成功地构建了一个脚本来解析和遍历我的节点应用程序的文件,并且能够按预期找到包含 fooMethod
的所有方法。
假设所有方法的主体都包含在 {
和 }
中,我会采用这样的方法来获得最终的正则表达式:
- 首先,找到一个正则表达式来获取各个方法。这可以使用这个正则表达式来完成:
exports\.(\w+)(\s|.)*?\{(\s|.)*?\}
- 接下来,我们感兴趣的是那些在关闭之前里面有
fooMethod
的方法。因此,按此顺序查找}
或fooMethod.*}
。因此,让我们将搜索fooMethod
的组命名为FOO
,并将调用它的方法的名称命名为METH
。当我们迭代匹配时,如果组FOO
出现在匹配中,我们将使用相应的METH
组,否则我们将拒绝它。
exports\.(?<METH>\w+)(\s|.)*?\{(\s|.)*?(\}|(?<FOO>fooMethod)(\s|.)*?\})
解释:
exports\.(?<METH>\w+)
: 直到方法名(你已经覆盖了这个)(\s|.)*?\{(\s|.)*?
:{
之前和之后的一些代码,非贪心,以便后面的组优先(\}|(?<FOO>fooMethod)(\s|.)*?\})
:这有两部分:\}
:匹配方法结束分隔符,或(?<FOO>fooMethod)(\s|.)*?\})
:调用fooMethod
后跟可选代码和方法关闭分隔符。
这里有一个 JavaScript 代码来演示这个:
let p = /exports\.(?<METH>\w+)(\s|.)*?\{(\s|.)*?(\}|(?<FOO>fooMethod)(\s|.)*?\})/g
let input = `exports.methodOne = async user_id => {
// other method contents
};
exports.methodTwo = async user_id => {
// other method contents
fooMethod();
};
exports.methodThree = async user_id => {
// other method contents
fooMethod();
};';`
let match = p.exec( input );
while( match !== null) {
if( match.groups.FOO !== undefined ) console.log( match.groups.METH );
match = p.exec( input )
}
此正则表达式(仅)匹配包含对 fooMethod();
(?<=exports\.)\w+(?=[^{]+\{[^}]+fooMethod\(\)[^}]+};)
参见live demo。
正则表达式并不是解决这个问题所有部分的最佳工具,理想情况下我们可以依赖更高级别的东西,一个解析器。
一种方法是让 javascript 在加载和执行期间自行解析。如果您的节点模块不包含任何可自行执行的内容(或至少不包含任何与以下内容冲突的内容),您可以将其放在模块的底部,然后 运行 使用 node mod.js
.
console.log(Object.keys(exports).filter(fn => exports[fn].toString().includes("fooMethod(")));
(在下面的评论中显示以上是不可能的。)
另一种选择是使用像 https://github.com/acornjs/acorn 这样的库(还有其他选项)来编写一些其他 javascript 来解析您的原始目标 javascript,那么您将拥有您可以使用树结构来执行匹配,并最终 return 您之后的函数名称。我不是该库的专家,所以很遗憾我没有适合您的示例代码。