Замените строку в файле на nodejs

Я использую md5 grunt task для создания имен файлов MD5. Теперь я хочу переименовать источники в html-файле с новым именем файла в обратном вызове задачи. Интересно, как проще всего это сделать.

8 ответов


Вы можете использовать простое регулярное выражение:

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

поскольку replace не работал для меня, я создал простой пакет npm replace-in-file для быстрой замены текста в одном или нескольких файлах. Это частично основано на ответе @asgoth.

Правка (3 Октября 2016): пакет теперь поддерживает обещания и глобусы, и инструкции по использованию были обновлены, чтобы отразить это.

Edit (16 Марта 2018): пакет накопил более 100k ежемесячных загрузок сейчас и был расширенный с дополнительными функциями, а также инструментом 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,
});

вы также можете использовать функция 'СЭД' это часть ShellJS ...

 $ npm install [-g] shelljs


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

посетить ShellJs.org Для больше примеров.


вы можете обрабатывать файл во время чтения с помощью потоков. Это похоже на использование буферов, но с более удобным 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');

я столкнулся с проблемами при замене небольшого заполнителя большой строкой кода.

Я делаю:

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

я понял, что проблема заключалась в специальных шаблонах замены JavaScript, описанных здесь. Поскольку код, который я использовал в качестве заменяющей строки, имел некоторые $ в нем он испортил выход.

моим решением было использовать опцию замены функции, которая не делает никакой специальной замены:

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

вместо этого я бы использовал дуплексный поток. как задокументировано здесь NodeJS doc duplex streams

преобразование потока дуплекс ручья, где выход вычисляется в каким-то образом от входа.


ES2017 / 8 для узла 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
}

Примечание, только для небольших файлов, поскольку они будут считываться в память.