ฉันใช้งานmd5 gruntเพื่อสร้างชื่อไฟล์ MD5 ตอนนี้ฉันต้องการเปลี่ยนชื่อแหล่งที่มาในไฟล์ HTML ด้วยชื่อไฟล์ใหม่ในการเรียกกลับของงาน ฉันสงสัยว่าอะไรเป็นวิธีที่ง่ายที่สุดในการทำเช่นนี้
ฉันใช้งานmd5 gruntเพื่อสร้างชื่อไฟล์ MD5 ตอนนี้ฉันต้องการเปลี่ยนชื่อแหล่งที่มาในไฟล์ HTML ด้วยชื่อไฟล์ใหม่ในการเรียกกลับของงาน ฉันสงสัยว่าอะไรเป็นวิธีที่ง่ายที่สุดในการทำเช่นนี้
คำตอบ:
คุณสามารถใช้ regex ง่าย ๆ :
var result = fileAsString.replace(/string to be replaced/g, 'replacement');
ดังนั้น...
var fs = require('fs')
fs.readFile(someFile, 'utf8', function (err,data) {
if (err) {
return console.log(err);
}
var result = data.replace(/string to be replaced/g, 'replacement');
fs.writeFile(someFile, result, 'utf8', function (err) {
if (err) return console.log(err);
});
});
เนื่องจากการแทนที่ไม่ได้ผลสำหรับฉันฉันได้สร้างแพ็คเกจ NPM แบบง่ายๆเพื่อแทนที่ข้อความในไฟล์อย่างน้อยหนึ่งไฟล์ มันขึ้นอยู่กับคำตอบของ @ asgoth บางส่วน
แก้ไข (3 ตุลาคม 2559) : แพคเกจรองรับสัญญาและ globs และคำแนะนำการใช้งานได้รับการปรับปรุงเพื่อสะท้อนถึงสิ่งนี้
แก้ไข (16 มีนาคม 2561) : แพ็คเกจดังกล่าวได้รับการดาวน์โหลดมากกว่า 100,000 ครั้งต่อเดือนและได้ขยายคุณสมบัติเพิ่มเติมรวมถึงเครื่องมือ CLI
ติดตั้ง:
npm install replace-in-file
ต้องใช้โมดูล
const replace = require('replace-in-file');
ระบุตัวเลือกการเปลี่ยน
const options = {
//Single file
files: 'path/to/file',
//Multiple files
files: [
'path/to/file',
'path/to/other/file',
],
//Glob(s)
files: [
'path/to/files/*.html',
'another/**/*.path',
],
//Replacement to make (string or regex)
from: /Find me/g,
to: 'Replacement',
};
การแทนที่แบบอะซิงโครนัสพร้อมสัญญา:
replace(options)
.then(changedFiles => {
console.log('Modified files:', changedFiles.join(', '));
})
.catch(error => {
console.error('Error occurred:', error);
});
การแทนที่แบบอะซิงโครนัสด้วยการโทรกลับ:
replace(options, (error, changedFiles) => {
if (error) {
return console.error('Error occurred:', error);
}
console.log('Modified files:', changedFiles.join(', '));
});
การแทนที่แบบซิงโครนัส:
try {
let changedFiles = replace.sync(options);
console.log('Modified files:', changedFiles.join(', '));
}
catch (error) {
console.error('Error occurred:', error);
}
บางทีโมดูล "replace" ( www.npmjs.org/package/replace ) อาจเหมาะกับคุณเช่นกัน มันจะไม่ต้องการให้คุณอ่านแล้วเขียนไฟล์
ดัดแปลงจากเอกสาร:
// install:
npm install replace
// require:
var replace = require("replace");
// use:
replace({
regex: "string to be replaced",
replacement: "replacement string",
paths: ['path/to/your/file'],
recursive: true,
silent: true,
});
คุณสามารถใช้ฟังก์ชั่น 'sed' ที่เป็นส่วนหนึ่งของ ShellJS ...
$ npm install [-g] shelljs
require('shelljs/global');
sed('-i', 'search_pattern', 'replace_pattern', file);
เยี่ยมชมShellJs.orgเพื่อดูตัวอย่างเพิ่มเติม
shx
ให้คุณเรียกใช้จากสคริปต์ npm, ShellJs.org แนะนำให้มัน github.com/shelljs/shx
คุณสามารถประมวลผลไฟล์ในขณะที่กำลังอ่านโดยใช้สตรีม มันเหมือนกับการใช้บัฟเฟอร์ แต่กับ API ที่สะดวกกว่า
var fs = require('fs');
function searchReplaceFile(regexpFind, replace, cssFileName) {
var file = fs.createReadStream(cssFileName, 'utf8');
var newCss = '';
file.on('data', function (chunk) {
newCss += chunk.toString().replace(regexpFind, replace);
});
file.on('end', function () {
fs.writeFile(cssFileName, newCss, function(err) {
if (err) {
return console.log(err);
} else {
console.log('Updated!');
}
});
});
searchReplaceFile(/foo/g, 'bar', 'file.txt');
bufferSize
สตริงที่ยาวกว่าที่คุณกำลังแทนที่และบันทึกอันสุดท้ายและเชื่อมต่อกับอันปัจจุบันที่คุณสามารถหลีกเลี่ยงปัญหานั้นได้หรือไม่
ฉันพบปัญหาเมื่อแทนที่ตัวยึดตำแหน่งขนาดเล็กด้วยรหัสสตริงจำนวนมาก
ฉันกำลังทำ:
var replaced = original.replace('PLACEHOLDER', largeStringVar);
ฉันคิดว่าปัญหาคือ JavaScript ของรูปแบบการเปลี่ยนพิเศษที่อธิบายไว้ที่นี่ เนื่องจากรหัสที่ฉันใช้เป็นสายอักขระการแทนที่มีบางอย่าง$
อยู่ในนั้นจึงทำให้การส่งออกเกิดความสับสน
โซลูชันของฉันคือใช้ตัวเลือกการแทนที่ฟังก์ชันซึ่งไม่ได้ทำการทดแทนพิเศษใด ๆ :
var replaced = original.replace('PLACEHOLDER', function() {
return largeStringVar;
});
ES2017 / 8 สำหรับ Node 7.6+ ด้วยไฟล์เขียนชั่วคราวเพื่อทดแทนอะตอมมิก
const Promise = require('bluebird')
const fs = Promise.promisifyAll(require('fs'))
async function replaceRegexInFile(file, search, replace){
let contents = await fs.readFileAsync(file, 'utf8')
let replaced_contents = contents.replace(search, replace)
let tmpfile = `${file}.jstmpreplace`
await fs.writeFileAsync(tmpfile, replaced_contents, 'utf8')
await fs.renameAsync(tmpfile, file)
return true
}
หมายเหตุเฉพาะไฟล์ขนาดเล็กเท่านั้นเนื่องจากจะถูกอ่านในหน่วยความจำ
บน Linux หรือ Mac Keep ง่ายและใช้ sed กับเชลล์ ไม่ต้องใช้ไลบรารีภายนอก รหัสต่อไปนี้ทำงานบน Linux
const shell = require('child_process').execSync
shell(`sed -i "s!oldString!newString!g" ./yourFile.js`)
รูปแบบของ sed นั้นแตกต่างกันเล็กน้อยบน Mac ฉันไม่สามารถทดสอบได้ในตอนนี้ แต่ฉันเชื่อว่าคุณเพียงแค่ต้องเพิ่มสตริงว่างหลังจาก "-i":
const shell = require('child_process').execSync
shell(`sed -i "" "s!oldString!newString!g" ./yourFile.js`)
"g" หลังจากสุดท้าย "!" ทำให้ sed แทนที่อินสแตนซ์ทั้งหมดในบรรทัด ลบออกและจะเกิดขึ้นครั้งแรกต่อบรรทัดเท่านั้น
การขยายคำตอบของ @ Sanbor วิธีที่มีประสิทธิภาพที่สุดในการทำเช่นนี้คือการอ่านไฟล์ต้นฉบับเป็นสตรีมและจากนั้นสตรีมแต่ละก้อนเป็นไฟล์ใหม่จากนั้นจึงแทนที่ไฟล์ต้นฉบับด้วยไฟล์ใหม่
async function findAndReplaceFile(regexFindPattern, replaceValue, originalFile) {
const updatedFile = `${originalFile}.updated`;
return new Promise((resolve, reject) => {
const readStream = fs.createReadStream(originalFile, { encoding: 'utf8', autoClose: true });
const writeStream = fs.createWriteStream(updatedFile, { encoding: 'utf8', autoClose: true });
// For each chunk, do the find & replace, and write it to the new file stream
readStream.on('data', (chunk) => {
chunk = chunk.toString().replace(regexFindPattern, replaceValue);
writeStream.write(chunk);
});
// Once we've finished reading the original file...
readStream.on('end', () => {
writeStream.end(); // emits 'finish' event, executes below statement
});
// Replace the original file with the updated file
writeStream.on('finish', async () => {
try {
await _renameFile(originalFile, updatedFile);
resolve();
} catch (error) {
reject(`Error: Error renaming ${originalFile} to ${updatedFile} => ${error.message}`);
}
});
readStream.on('error', (error) => reject(`Error: Error reading ${originalFile} => ${error.message}`));
writeStream.on('error', (error) => reject(`Error: Error writing to ${updatedFile} => ${error.message}`));
});
}
async function _renameFile(oldPath, newPath) {
return new Promise((resolve, reject) => {
fs.rename(oldPath, newPath, (error) => {
if (error) {
reject(error);
} else {
resolve();
}
});
});
}
// Testing it...
(async () => {
try {
await findAndReplaceFile(/"some regex"/g, "someReplaceValue", "someFilePath");
} catch(error) {
console.log(error);
}
})()
ฉันจะใช้สตรีมเพล็กซ์แทน เช่นเอกสารที่นี่nodejs doc สตรีมเพล็กซ์
กระแสการแปลงเป็นกระแสข้อมูลแบบดูเพล็กซ์ที่มีการคำนวณเอาท์พุทในบางวิธีจากอินพุต
<p>Please click in the following {{link}} to verify the account</p>
function renderHTML(templatePath: string, object) {
const template = fileSystem.readFileSync(path.join(Application.staticDirectory, templatePath + '.html'), 'utf8');
return template.match(/\{{(.*?)\}}/ig).reduce((acc, binding) => {
const property = binding.substring(2, binding.length - 2);
return `${acc}${template.replace(/\{{(.*?)\}}/, object[property])}`;
}, '');
}
renderHTML(templateName, { link: 'SomeLink' })
เพื่อให้แน่ใจว่าคุณสามารถปรับปรุงฟังก์ชันเทมเพลตการอ่านเพื่ออ่านเป็นสตรีมและเขียนไบต์ต่อบรรทัดเพื่อให้มีประสิทธิภาพมากขึ้น