2013-01-05 18 views

risposta

148

È possibile utilizzare semplice espressione regolare:

var result = fileAsString.replace(/string to be replaced/g, 'replacement'); 

Quindi ...

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); 
    }); 
}); 
+0

Certo, ma devo leggere il file sostituire il testo e poi scrivere di nuovo il file, o c'è un modo più semplice, mi dispiace sono più un ragazzo di frontend. –

+0

Forse c'è un modulo nodo per raggiungere questo obiettivo, ma non ne sono a conoscenza. Aggiunto un esempio completo btw. – asgoth

+2

piccolo errore, sostituire alla riga 6 'someFile' con 'data' – Zax

20

È inoltre possibile utilizzare la funzione di 'sed' che fa parte di ShellJS ...

$ npm install [-g] shelljs 


require('shelljs/global'); 
sed('-i', 'search_pattern', 'replace_pattern', file); 

Visita ShellJs.org per ulteriori esempi.

+0

questa sembra la soluzione più pulita :) – Yerken

+1

'shx' consente di eseguire da script npm, ShellJs.org lo ha consigliato. https://github.com/shelljs/shx –

+0

Mi piace anche questo. Meglio un oneliner, che un modulo npm, ma linee sureverali di codice ^^ – suther

24

Forse il modulo "sostituisci" (www.npmjs.org/package/replace) funzionerebbe anche 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, 
}); 
+0

Sai come si può filtrare per estensione file nei percorsi? qualcosa di simile ai percorsi: ['percorso/a/tuo/file/*. js'] -> non funziona – Kalamarico

+0

È possibile utilizzare il nodo-glob per espandere i modelli glob a un array di percorsi e quindi scorrere su di essi. – RobW

+2

Questo è bello, ma è stato abbandonato. Vedi http://stackoverflow.com/a/31040890/1825390 per un pacchetto gestito se si desidera una soluzione pronta all'uso. – xavdid

24

Dal replace non funzionava per me, ho creato un semplice pacchetto NPM replace-in-file di 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 glob e le istruzioni di utilizzo sono state aggiornate per riflettere questo.

Installare:

npm install replace-in-file 

Richiede modulo

const replace = require('replace-in-file'); 

Specificare 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 asincrono con promesse:

replace(options) 
    .then(changedFiles => { 
    console.log('Modified files:', changedFiles.join(', ')); 
    }) 
    .catch(error => { 
    console.error('Error occurred:', error); 
    }); 

sostituzione asincrono con callback:

replace(options, (error, changedFiles) => { 
    if (error) { 
    return console.error('Error occurred:', error); 
    } 
    console.log('Modified files:', changedFiles.join(', ')); 
}); 

sostituzione sincrono:

try { 
    let changedFiles = replace.sync(options); 
    console.log('Modified files:', changedFiles.join(', ')); 
} 
catch (error) { 
    console.error('Error occurred:', error); 
} 
5

Si potrebbe elaborare il file durante la lettura utilizzando i flussi. È come usare i buffer ma con un'API più conveniente.

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'); 
+1

Ma ... e se il pezzo divide la stringa regexpFind? L'intenzione non fallisce allora? –

+0

Questo è un ottimo punto. Mi chiedo se impostando un 'bufferSize' più lungo della stringa che stai sostituendo e salvando l'ultimo blocco e concatenando con quello corrente potresti evitare questo problema. – sanbor

+0

Probabilmente questo snippet dovrebbe anche essere migliorato scrivendo il file modificato direttamente nel filesystem piuttosto che creando una grande variabile in quanto il file potrebbe essere più grande della memoria disponibile. – sanbor

0

Vorrei utilizzare un flusso duplex invece. come documentato qui nodejs doc duplex streams

Un Transform flusso è un flusso Duplex in cui l'uscita è calcolato in qualche modo dall'ingresso.

1

Mi sono imbattuto in problemi quando si sostituiva un piccolo segnaposto con una grande stringa di codice.

che stavo facendo:

var replaced = original.replace('PLACEHOLDER', largeStringVar); 

ho capito che il problema era modelli di ricambio appositamente di JavaScript, descritto here. Dal momento che il codice che stavo usando come stringa di sostituzione aveva un numero di $ in esso, stava rovinando l'output.

La mia soluzione era quella di utilizzare l'opzione di sostituzione funzione, che non fa alcuna sostituzione speciale:

var replaced = original.replace('PLACEHOLDER', function() { 
    return largeStringVar; 
}); 
0

ES2017/8 per il nodo 7.6+ con un file di scrittura temporanea 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 dimensioni ridotte man mano che verranno letti in memoria.

+0

Non c'è bisogno di 'bluebird', usa nativo' Promise' e ​​[util.promisify] (https://nodejs.org/dist/latest-v8.x/docs/api/util.html#util_util_promisify_original). –

+0

@FranciscoMateo Vero, ma oltre 1 o 2 funzioni promisifyAll è ancora super utile. – Matt

Problemi correlati