有许多示例用于匹配带或不带扩展名和路径的文件名。但是,我发现我的任务变化似乎更复杂。它是关于node.js require()
语句中的模块名称,其中扩展名是可选的,因此它可能存在与否。
我实际上相当远,如果这一点太复杂,我可以轻松地与我所拥有的一起生活。然而,好奇心驱使我向社区提问。在这些尝试的大部分时间里,我真的想知道它是如何完成的!
注意当然我可以轻松解决正则表达式之外的问题,然后删除可能存在的任何文件扩展名。我现在只是好奇它可以在正则表达式中完成。
我试了好几个小时,很多尝试使用先行表达的失败尝试,我想我并没有完全掌握它们(之前从未使用它们)。我甚至没有开始尝试检测已评论的陈述,如果有人为这种特殊情况提供解决方案,那只会是奖金,但
我试图在我无法控制的文件中匹配路径+文件名。它们甚至可能被缩小,所以我不会依赖于终点,或者它很容易。
请参阅下面的演示代码。示例测试文件故意看起来有点混乱,我试图把我可能想到的所有奇怪的组合放入我可能遇到的并且我的正则表达式必须处理。
可运行示例之前的一些可选背景:
有一件事特别适用于我的具体情况,但该部分已经解决,请参阅下文:我不会尝试匹配任何路径,只有三种情况:./
,../lib/
和&# 34;" (没有)。那是因为这是关于动态模块加载的,而模块是node.js(没有前缀,只有一些允许),核心库(../lib/
)的一部分或者注定要在某些地方动态加载runtime(./
- 该路径指示此类模块的代码尝试加载另一个此类模块)。我保留了文件系统路径,以便在开发过程中代码检查器如Flow和IDE本身有机会找到模块,但在运行时至少第3种模块不会在文件系统上。
这就是为什么在导入到存储期间我尝试解析它们的require语句:为了维护它们的CommonJS(node.js)同步特性,在实际加载请求的动态模块之前,我加载所有依赖项(递归)。为此我需要收集每个模块" require() - s"通过解析它,当我把它存储。我只是说作为可选信息,对于上下文,我无法控制,所以我毫不怀疑(in)是否可行(为什么我的描述中仍然缺少这样做。那个系统将改变,而不是现在。
这是可运行的测试用例,理想情况下我会有没有可选扩展名的名称,并删除了两个已注释掉的匹配项:
const testText: string = `
/**
* There are 8 active require() statements in here and 2 commented-out ones.
*/
const fs = require('fs'); require("../lib/store.js"); let t = require("crypto");
//OtherStuff: type defs comments etc.
let iah = require("./imap-account-handler.js"); //let iah = require("./inactive");
//let iah = require("./imap.js");
require("./imap-mailbox-handler");
const mX = require("./modX.js"); require("./modX.js"); require("./modY.js");
otherStuff();
otherStuff();
`;
const regex: RegExp = new RegExp(
// 1) Start indicator (account for allowed whitespace characters)
'require\\s*\\(\\s*["\']' +
// 2) match[1]: optional group for the prefix, which can only(!) be
// either "../lib" or "./"
'(' +
// 2.1) ...either a prefix indicating a core "One" module
// (captured by parent group)
'(?:\\.\\./lib/)' +
'|' +
// 2.2) ...or a prefix indicating a dynamic module
// (captured by parent group)
'(?:\\./)' +
')?' +
// 3) match[2]: Actual module name with or without file ending. We
// exclude the character that stands for the directory hierarchy
// and the two possible quote characters, everything else is
// allowed: This is not a check for name validity!
'([^/\\"\']+)' +
// 4) End indicator
'["\']\\s*\\)',
// 5) Flag "g" (global) There can be many "require(...)" commands.
'g'
);
let m: {[index: number]: string, index: number, input: string};
let count: number = 1;
while (m = regex.exec(testText)) {
console.log(
`${count++}: Prefix ${m[1] || '(none)'} ${'\t'} Name ${m[2] || '(none)'}`
);
}

答案 0 :(得分:2)
您可以使用单独的替换命令删除首先注释掉的语句(请参阅第let cleanComments
行)。然后,正则表达式:
需要
(左括号
['"]任何一种类型的引用
(./|../lib/)?可选的前缀捕获
([^'"] +?)捕获任何不是引用的内容组
(?:。js)文件扩展名的可选非捕获组
['"]关闭任何一种类型的引用
const testText: string = `
/**
* There are 8 active require() statements in here and 2 commented-out ones.
*/
const fs = require('fs'); require("../lib/store.js"); let t = require("crypto");
//OtherStuff: type defs comments etc.
let iah = require("./imap-account-h.andler.js"); //let iah = require("./inactive");
//let iah = require("./imap.js");
require("./imap-mailbox-handler");
const mX = require("./modX.js"); require("./modX.js"); require("./modY.js");
otherStuff();
otherStuff();
`;
const regex = /require\(['"](\.\/|\.\.\/lib\/)?([^'"]+?)(?:\.js)?['"]/g
let m: {[index: number]: string, index: number, input: string};
let count: number = 1;
let cleanComments = testText.replace(/\/\/.+/g,"")
while (m = regex.exec(cleanComments)) {
console.log(
`${count++}: Prefix ${m[1] || '(none)'} ${'\t'} Name ${m[2] || '(none)'}`
);
}