Uso l' attività grunt md5 per generare nomi di file MD5. Ora voglio rinominare le fonti nel file HTML con il nuovo nome file nel callback dell'attività. Mi chiedo quale sia il modo più semplice per farlo.
Uso l' attività grunt md5 per generare nomi di file MD5. Ora voglio rinominare le fonti nel file HTML con il nuovo nome file nel callback dell'attività. Mi chiedo quale sia il modo più semplice per farlo.
Risposte:
Puoi usare regex semplice:
var result = fileAsString.replace(/string to be replaced/g, 'replacement');
Così...
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);
});
});
Dal momento che sostituire non funzionava per me, ho creato un semplice pacchetto npm repl -in-file per sostituire rapidamente il testo in uno o più file. È parzialmente basato sulla risposta di @ asgoth.
Modifica (3 ottobre 2016) : il pacchetto ora supporta promesse e globs e le istruzioni per l'uso sono state aggiornate per riflettere questo.
Modifica (16 marzo 2018) : il pacchetto ha accumulato oltre 100.000 download mensili ora ed è stato esteso con funzionalità aggiuntive e uno strumento CLI.
Installare:
npm install replace-in-file
Modulo richiesto
const replace = require('replace-in-file');
Specifica le opzioni di sostituzione
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',
};
Sostituzione asincrona con promesse:
replace(options)
.then(changedFiles => {
console.log('Modified files:', changedFiles.join(', '));
})
.catch(error => {
console.error('Error occurred:', error);
});
Sostituzione asincrona con callback:
replace(options, (error, changedFiles) => {
if (error) {
return console.error('Error occurred:', error);
}
console.log('Modified files:', changedFiles.join(', '));
});
Sostituzione sincrona:
try {
let changedFiles = replace.sync(options);
console.log('Modified files:', changedFiles.join(', '));
}
catch (error) {
console.error('Error occurred:', error);
}
Forse anche il modulo "sostituisci" ( www.npmjs.org/package/replace ) funzionerebbe per te. Non richiederebbe di leggere e quindi scrivere il file.
Adattato dalla documentazione:
// 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,
});
readFile()
e writeFile()
proprio come la risposta accettata.
Puoi anche usare la funzione 'sed' che fa parte di ShellJS ...
$ npm install [-g] shelljs
require('shelljs/global');
sed('-i', 'search_pattern', 'replace_pattern', file);
Visita ShellJs.org per altri esempi.
shx
ti permette di eseguire da script npm, ShellJs.org lo ha raccomandato. github.com/shelljs/shx
È possibile elaborare il file durante la lettura utilizzando gli stream. È come usare i buffer ma con un'API più comoda.
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
più lungo della stringa che stai sostituendo e salvando l'ultimo pezzo e concatenandolo con quello attuale potresti evitare questo problema.
Ho riscontrato problemi durante la sostituzione di un segnaposto piccolo con una stringa di codice di grandi dimensioni.
Stavo facendo:
var replaced = original.replace('PLACEHOLDER', largeStringVar);
Ho capito che il problema erano gli schemi di sostituzione speciali di JavaScript, descritti qui . Poiché il codice che stavo usando come stringa di sostituzione ne conteneva un po $
', stava rovinando l'output.
La mia soluzione era quella di utilizzare l'opzione di sostituzione della funzione, che NON esegue alcuna sostituzione speciale:
var replaced = original.replace('PLACEHOLDER', function() {
return largeStringVar;
});
ES2017 / 8 per Nodo 7.6+ con un file di scrittura temporaneo per la sostituzione atomica.
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
}
Nota, solo per file di piccole dimensioni in quanto verranno letti in memoria.
Su Linux o Mac, keep è semplice e basta usare sed con la shell. Non sono necessarie librerie esterne. Il seguente codice funziona su Linux.
const shell = require('child_process').execSync
shell(`sed -i "s!oldString!newString!g" ./yourFile.js`)
La sintassi sed è leggermente diversa su Mac. Non posso provarlo in questo momento, ma credo che devi solo aggiungere una stringa vuota dopo "-i":
const shell = require('child_process').execSync
shell(`sed -i "" "s!oldString!newString!g" ./yourFile.js`)
La "g" dopo la finale "!" fa sed sostituire tutte le istanze su una linea. Rimuoverlo e verrà sostituita solo la prima occorrenza per riga.
Espandendo la risposta di @ Sanbor, il modo più efficace per farlo è leggere il file originale come flusso, quindi anche eseguire lo streaming di ogni blocco in un nuovo file e infine sostituire il file originale con il nuovo file.
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);
}
})()
Vorrei invece utilizzare un flusso duplex. come documentato qui stream document duplex di nodejs
Un flusso Transform è un flusso Duplex in cui l'output viene calcolato in qualche modo dall'input.
<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' })
sicuramente puoi migliorare la funzione del modello di lettura per leggere come stream e comporre i byte per riga per renderlo più efficiente