const fs = require('fs');
|
const readline = require('readline');
|
const path = require('path');
|
|
/**
|
* 尋找 Pascal 檔案中的影像處理相關關鍵字,並生成 CSV 輸出。
|
* @param {string} filePath - Pascal 檔案路徑
|
* @param {string} outputCsv - 輸出的 CSV 檔案名稱
|
*/
|
async function findImageKeywords(filePath, keywordsStr, exclusionStr, outputCsv) {
|
const keeper = {}
|
// 拆分並使用 Set 移除重複的關鍵字
|
const keywords = [...new Set(keywordsStr.split('|'))];
|
const exclusion = exclusionStr ? [...new Set(exclusionStr.split('|'))] : [];
|
|
// 用於匹配 Delphi procedure 或 function 的正規表達式
|
const methodPattern = /^\s*(?:procedure|function)\s+([a-zA-Z0-9_\.]+)/i;
|
|
const results = [];
|
let currentMethod = "Global_Or_Interface"; // 預設狀態 (尚未進入任何方法)
|
|
if (!fs.existsSync(filePath)) {
|
console.error(`❌ 錯誤: 找不到指定的檔案 '${filePath}'`);
|
console.log("請確保檔案名稱正確,並與此腳本放在同一目錄下。");
|
return;
|
}
|
|
console.log(`🔍 開始掃描檔案: ${filePath} ...\n`);
|
const fileName = path.basename(filePath);
|
|
// 建立逐行讀取流 (使用 latin1 讀取以避免 Big5 中文字元在原生 Node 環境報錯)
|
// 由於我們只比對英文關鍵字,編碼不會影響比對結果
|
const fileStream = fs.createReadStream(filePath, {encoding: 'latin1'});
|
const rl = readline.createInterface({
|
input: fileStream,
|
crlfDelay: Infinity
|
});
|
|
let lineNum = 0;
|
|
for await (const line of rl) {
|
lineNum++;
|
|
// 檢查是否進入了新的方法實作區塊
|
const methodMatch = line.match(methodPattern);
|
if (methodMatch) {
|
currentMethod = methodMatch[1];
|
}
|
|
const lineLower = line.toLowerCase();
|
|
// 檢查該行是否包含我們關注的關鍵字
|
for (const kw of keywords) {
|
if (lineLower.includes(kw.toLowerCase()) && !exclusion.some((_)=>lineLower.includes(_.toLowerCase()))) {
|
keeper[currentMethod] ??= new Set([])
|
if (keeper[currentMethod].has(kw))
|
continue
|
keeper[currentMethod].add(kw)
|
results.push({
|
MethodName: currentMethod,
|
FileName: fileName,
|
LineNumber: lineNum,
|
Dependency: kw,
|
CodeSnippet: line.trim().replace(/"/g, '""') // 處理 CSV 雙引號跳脫
|
});
|
}
|
}
|
}
|
|
// 1. 輸出至 Console
|
console.log("-".repeat(90));
|
|
// 為了讓 Console 顯示更乾淨,我們按方法名稱進行分組顯示
|
const groupedResults = results.reduce((acc, curr) => {
|
if (!acc[curr.MethodName]) acc[curr.MethodName] = [];
|
acc[curr.MethodName].push(curr);
|
return acc;
|
}, {});
|
|
for (const [method, items] of Object.entries(groupedResults)) {
|
// 收集該方法內找到的所有相依關鍵字 (去重複)
|
const deps = [...new Set(items.map(i => i.Dependency))].join(', ');
|
const lines = [...new Set(items.map(i => i.LineNumber))].join(', ');
|
|
console.log(`${method.padEnd(30)} | ${fileName.padEnd(20)} | ${lines.padEnd(5)} | ${deps}`);
|
}
|
|
console.log(`\n✅ 掃描成功!共找到 ${results.length} 次相依引用。`);
|
|
// 2. 輸出至 CSV 檔案
|
// 加入 BOM 以確保 Excel 能正確解析 UTF-8 中文
|
const csvHeader = '\uFEFF[ ],方法名,所在檔名,行號,引用了什麼相依,方法描述(請手動填寫),原始程式碼片段\n';
|
|
const csvContent = results.map(r =>
|
`[V],"${r.MethodName}","${r.FileName}","${r.LineNumber}","${r.Dependency}","","${r.CodeSnippet}"`
|
).join('\n');
|
if (results.length) {
|
fs.writeFileSync(outputCsv, csvHeader + csvContent, 'utf8');
|
}
|
console.log(`📁 詳細結果已匯出至: ${outputCsv} (可直接用 Excel 打開)`);
|
return {
|
csvHeader,
|
csvContent
|
}
|
}
|
|
module.exports = {
|
findImageKeywords
|
}
|