wake-up-neo.com

Ersetzen Sie eine Zeichenfolge in einer Datei durch nodejs

Ich verwende die md5 grunt task , um MD5-Dateinamen zu generieren. Nun möchte ich die Quellen in der HTML-Datei mit dem neuen Dateinamen im Callback der Task umbenennen. Ich frage mich, was der einfachste Weg ist, dies zu tun.

114

Sie könnten einfache Regex verwenden:

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

So...

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);
  });
});
213
asgoth

Da replace für mich nicht funktioniert hat, habe ich ein einfaches npm-Paket erstellt - replace-in-file , um Text in einer oder mehreren Dateien schnell zu ersetzen. Es basiert teilweise auf @ asgoths Antwort.

Edit (3. Oktober 2016): Das Paket unterstützt jetzt Versprechen und Globs. Die Gebrauchsanweisungen wurden entsprechend aktualisiert.

Edit (16. März 2018): Das Paket umfasst inzwischen mehr als 100.000 Downloads pro Monat und wurde um zusätzliche Funktionen sowie ein CLI-Tool erweitert.

Installieren:

npm install replace-in-file

Modul erforderlich

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

Legen Sie Ersatzoptionen fest

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',
};

Asynchroner Ersatz mit Versprechen:

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

Asynchroner Ersatz mit Callback:

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

Synchrone Ersetzung:

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

Vielleicht würde das "Ersetzen" -Modul ( www.npmjs.org/package/replace ) auch für Sie funktionieren. Sie müssen die Datei nicht lesen und dann schreiben.

Angepasst aus der Dokumentation:

// 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,
});
29
Slack Undertow

Sie können auch die 'sed'-Funktion verwenden, die zu ShellJS gehört ...

 $ npm install [-g] shelljs


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

Besuchen Sie ShellJs.org für weitere Beispiele.

24
Tony O'Hagan

Sie können die Datei während des Lesens mithilfe von Streams verarbeiten. Es ist wie bei der Verwendung von Puffern, aber mit einer bequemeren 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');
5
sanbor

ES2017/8 für Knoten 7.6+ mit einer temporären Schreibdatei für atomaren Austausch.

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
}

Hinweis: Nur für kleine Dateien, da diese in den Speicher gelesen werden. 

1
Matt

Ich bin auf Probleme gestoßen, als ich einen kleinen Platzhalter durch eine große Zeichenfolge ersetzt.

Ich habe getan:

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

Ich fand heraus, dass es sich bei JavaScript um spezielle Ersatzmuster handelte, die hier beschrieben werden. Da der Code, den ich als ersetzende Zeichenfolge verwendete, einen $ enthielt, war die Ausgabe durcheinander geraten.

Meine Lösung bestand darin, die Funktion zum Ersetzen von Funktionen zu verwenden, die KEINEN speziellen Austausch vornimmt:

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

Unter Linux oder Mac ist keep einfach und wird nur mit der Shell verwendet. Keine externen Bibliotheken erforderlich. Der folgende Code funktioniert unter Linux.

const Shell = require('child_process').execSync
Shell(`sed -i "s!oldString!newString!g" ./yourFile.js`)

Die sed-Syntax ist auf dem Mac etwas anders. Ich kann es momentan nicht testen, aber ich glaube, Sie müssen nur eine leere Zeichenfolge nach dem "-i" einfügen:

const Shell = require('child_process').execSync
Shell(`sed -i "" "s!oldString!newString!g" ./yourFile.js`)

Das "g" nach dem Finale "!" Lässt sed alle Instanzen in einer Zeile ersetzen. Entfernen Sie es, und nur das erste Vorkommen pro Zeile wird ersetzt.

0
777

Um die Antwort von @ Sanbor zu erweitern, ist es am effizientesten, die Originaldatei als Stream zu lesen und dann jeden Chunk in eine neue Datei zu streamen und die Originaldatei zuletzt durch die neue Datei zu ersetzen.

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);
  }
})()
0
sudo soul

Ich würde stattdessen einen Duplex-Stream verwenden. wie hier dokumentiert nodejs doc duplex streams

Ein Transformationsstrom ist ein Duplexstrom, bei dem die Ausgabe in .__ berechnet wird. etwas von der Eingabe entfernt.

0
pungggi