2016-12-01 124 views
1

很多匹配文件名有擴展名和路徑的例子。但是,我發現我的變化似乎更復雜。它是關於node.js require()語句中的模塊名稱,其中擴展名是可選的,因此它可能存在或不存在。正則表達式匹配路徑和文件名,擴展名可選,沒有換行符,忽略註釋

我其實已經很遠了,如果這一點太複雜了,我可以輕鬆地生活我所擁有的。然而,好奇心促使我問社區。花了大部分時間在這些嘗試後,我真的想知道它是如何完成的!

注意當然,我可以很容易地解決正則表達式之外的問題,之後刪除任何可能存在的文件擴展名。我現在只是好奇可以做以內的正則表達式。

我試了幾個小時,嘗試使用預見性表達式的嘗試失敗了許多,我想我沒有完全理解它們(以前從未使用它們)。我甚至沒有開始嘗試檢測評論的聲明,如果任何人有一個解決方案,這種特殊情況下,它只是一個獎金,但

我試圖匹配路徑+文件名,我不'無法控制。他們甚至可能會被縮小,所以我沒有依靠線索的結束,或者它會很容易。

請參閱下面的演示代碼。這個示例測試文件故意看起來有點亂,我嘗試着將所有我能想到的奇怪的組合放在一起,並且我的正則表達式不得不處理。


可運行示例之前一些可選的背景下進一步下跌:

有一件事是專門爲我的具體情況,但是這部分解決了,見下圖:我不嘗試匹配任何路徑,但只有三種情況:./,../lib/和「」(無)。這是因爲這是關於動態模塊加載,並且模塊是node.js(無前綴,只允許一些),核心庫(../lib/)的一部分或註定要在運行時從某處動態加載(./ - 該路徑指示這樣的模塊的代碼嘗試加載另一個這樣的模塊)。我將文件系統路徑保存在那裏,以便在開發過程中像Flow和IDE這樣的代碼檢查器有機會找到這些模塊,但是在運行時至少第三種模塊不在文件系統中。

這就是爲什麼在導入存儲過程中,我嘗試解析它們的require語句:爲了保持它們的CommonJS(node.js)同步性質,在實際加載請求的動態模塊之前,我加載所有依賴關係(遞歸地)。爲此,我需要通過解析它來收集每個模塊「require() - s」的內容。我只是說,作爲可選的信息片段,對於上下文,我無法控制這一點,所以我不知道如何(在)是可取的(爲什麼爲什麼仍然失蹤從我的描述)。該系統更改,只是不是現在。


下面是可運行的測試情況下,最好我本來的名字沒有可選的擴展,和兩個註釋掉的比賽中刪除:

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)'}` 
 
    ); 
 
}

回答

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)'}` 
 
    ); 
 
}
收盤報價組

+0

好的答案,不僅是因爲解決了評論問題,而且還簡化了正則表達式(使用'regex = /.../而不是'new RegExp('...')'),因此提高了可讀性。我只是提出了兩點小小的改進:1)cleanComments正則表達式可能會覆蓋「空評論」的情況:'/\/\/.*/'而不是'/\/\/.+/'; 2)路徑捕獲部分'([^'「] +?)'可能改爲'([^'」。] +)':也不包括點,它避免了'+?'(非貪婪)量詞,因此消耗更少的正則表達式引擎的步驟。 – cFreed

+1

我最初有'([^'「。+)'',但問題是它不適用於任何包含'.'的文件名(我將其中一個文件名更改爲'imap-account-h。 andler.js'來測試這個確切的場景)同樣對於評論來說,這是一個很好的總結,但在這種情況下,我們並不需要關心空的評論,因爲檢查的唯一理由是擺脫註釋-out需要語句 – jmcgriz

+0

是的,這就是偉大的人,被標記爲答案,我故意將它寫成一個字符串,因爲這是將它分散到多行的唯一方法,這樣我就可以分別爲每個組件添加雙反斜槓我認爲,從現在開始半年,我想優化編輯該表達式的速度,而不是代碼的速度,因爲這是某些東西的一部分,只能很少運行,如果只運行一次,可以運行 –