Javascript 用 nodejs 替换文件中的字符串

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14177087/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 15:56:03  来源:igfitidea点击:

Replace a string in a file with nodejs

javascriptnode.jsreplacegruntjs

提问by Andreas K?berle

I use the md5 grunt taskto generate MD5 filenames. Now I want to rename the sources in the HTML file with the new filename in the callback of the task. I wonder what's the easiest way to do this.

我使用md5 grunt 任务来生成 MD5 文件名。现在我想在任务的回调中使用新文件名重命名 HTML 文件中的源。我想知道什么是最简单的方法来做到这一点。

回答by asgoth

You could use simple regex:

您可以使用简单的正则表达式:

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

回答by Adam Reis

Since replace wasn't working for me, I've created a simple npm package replace-in-fileto quickly replace text in one or more files. It's partially based on @asgoth's answer.

由于 replace 对我不起作用,我创建了一个简单的 npm 包replace-in-file来快速替换一个或多个文件中的文本。它部分基于@asgoth 的回答。

Edit (3 October 2016): The package now supports promises and globs, and the usage instructions have been updated to reflect this.

编辑(2016 年 10 月 3 日):该包现在支持 promises 和 globs,并且使用说明已更新以反映这一点。

Edit (16 March 2018): The package has amassed over 100k monthly downloads now and has been extended with additional features as well as a CLI tool.

编辑(2018 年 3 月 16 日):该软件包现在每月下载量已超过 10 万次,并且已扩展了附加功能以及 CLI 工具。

Install:

安装:

npm install replace-in-file

Require module

需要模块

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

Specify replacement options

指定替换选项

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

Asynchronous replacement with promises:

异步替换承诺:

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

Asynchronous replacement with callback:

用回调异步替换:

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

Synchronous replacement:

同步替换:

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

回答by Slack Undertow

Perhaps the "replace" module (www.npmjs.org/package/replace) also would work for you. It would not require you to read and then write the file.

也许“替换”模块(www.npmjs.org/package/replace)也适合您。它不需要您读取然后写入文件。

Adapted from the documentation:

改编自文档:

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

回答by Tony O'Hagan

You can also use the 'sed' function that's part of ShellJS ...

您还可以使用 ShellJS 中的“sed”函数...

 $ npm install [-g] shelljs


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

Visit ShellJs.orgfor more examples.

访问ShellJs.org获取更多示例。

回答by sanbor

You could process the file while being read by using streams. It's just like using buffers but with a more convenient API.

您可以在使用流读取的同时处理文件。这就像使用缓冲区,但具有更方便的 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');

回答by anderspitman

I ran into issues when replacing a small placeholder with a large string of code.

我在用一大串代码替换一个小占位符时遇到了问题。

I was doing:

我在做:

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

I figured out the problem was JavaScript's special replacement patterns, described here. Since the code I was using as the replacing string had some $in it, it was messing up the output.

我发现问题是 JavaScript 的特殊替换模式,描述在这里。由于我用作替换字符串的代码中包含一些$内容,因此它弄乱了输出。

My solution was to use the function replacement option, which DOES NOT do any special replacement:

我的解决方案是使用函数替换选项,它不做任何特殊的替换:

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

回答by Matt

ES2017/8 for Node 7.6+ with a temporary write file for atomic replacement.

ES2017/8 for 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
}

Note, only for smallish files as they will be read into memory.

请注意,仅适用于较小的文件,因为它们将被读入内存。

回答by 777

On Linux or Mac, keep is simple and just use sed with the shell. No external libraries required. The following code works on Linux.

在 Linux 或 Mac 上,keep 很简单,只需在 shell 中使用 sed。不需要外部库。以下代码适用于 Linux。

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

The sed syntax is a little different on Mac. I can't test it right now, but I believe you just need to add an empty string after the "-i":

Mac 上的 sed 语法略有不同。我现在无法测试它,但我相信您只需要在“-i”之后添加一个空字符串:

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

The "g" after the final "!" makes sed replace all instances on a line. Remove it, and only the first occurrence per line will be replaced.

最后一个“!”后面的“g” 使 sed 替换一行中的所有实例。删除它,只有每行的第一次出现将被替换。

回答by sudo soul

Expanding on @Sanbor's answer, the most efficient way to do this is to read the original file as a stream, and then also stream each chunk into a new file, and then lastly replace the original file with the new file.

扩展@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);
  }
})()

回答by Ezzabuzaid

<p>Please click in the following {{link}} to verify the account</p>

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

for sure you can improve the reading template function to read as stream and compose the bytes by line to make it more efficient

确保您可以改进读取模板功能以读取为流并按行组合字节以使其更高效