我使用md5 grunt task生成MD5文件名。现在我想在任务的回调中使用新文件名重命名HTML文件中的源。我想知道最简单的方法是什么。
答案 0 :(得分:225)
您可以使用简单的正则表达式:
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);
});
});
答案 1 :(得分:52)
由于替换对我不起作用,我创建了一个简单的npm包replace-in-file来快速替换一个或多个文件中的文本。它部分基于@ asgoth的答案。
编辑(2016年10月3日):该软件包现在支持promises和globs,并且使用说明已更新以反映这一点。
编辑(2018年3月16日):该软件包现已每月下载超过10万次,并且已通过其他功能和CLI工具进行了扩展。
安装:
private class MyAdapter extends ArrayAdapter<String> {
private Integer[] mThumbIds = {
R.drawable.wraps_parisian,
R.drawable.wraps_beiruti_2,
R.drawable.wraps_berlin,
R.drawable.wraps_cyprus_wrap,
R.drawable.wraps_mexican_fajita,
R.drawable.wraps_megabite,
R.drawable.wraps_monaco,
R.drawable.wraps_hail_caesar,
R.drawable.wraps_philly_steak,
R.drawable.wraps_cheezzy_blt,
R.drawable.wraps_britannia,
R.drawable.wraps_ranchero,
R.drawable.wraps_ibiza,
};
LruCache<Integer, Bitmap> imageCache;
public MyAdapter(Context context, int resource, int textViewResourceId, String[] strings) {
super(context, resource, textViewResourceId, strings);
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
final int casheSize = maxMemory / 8 ;
imageCache = new LruCache<>(casheSize);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.categories_item, parent, false);
String[] names = getResources().getStringArray(R.array.wraps_names);
String[] prices = getResources().getStringArray(R.array.wraps_prices);
String[] ingredients = getResources().getStringArray(R.array.wraps_ingredients);
TextView item_name = (TextView) row.findViewById(R.id.items_name);
TextView item_price = (TextView) row.findViewById(R.id.item_price);
TextView item_ingredient = (TextView) row.findViewById(R.id.ingredients);
item_name.setText(names[position]);
item_price.setText(prices[position]);
item_ingredient.setText(ingredients[position]);
ImageView imageView = (ImageView) row.findViewById(R.id.item_image);
Bitmap bmp = BitmapFactory.decodeResource(getResources(), mThumbIds[position]);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.JPEG, 100, bos);
byte[] data = bos.toByteArray();
imageCache.put(position, bmp);
Bitmap bitmap = imageCache.get(position);
if(bitmap != null){
imageView.setImageBitmap(bitmap);
}
return row;
}
}
需要模块
npm install replace-in-file
指定替换选项
const replace = require('replace-in-file');
使用promises进行异步替换:
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(', '));
});
答案 2 :(得分:30)
也许&#34;替换&#34;模块(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,
});
答案 3 :(得分:24)
你也可以使用属于ShellJS的'sed'功能......
$ npm install [-g] shelljs
require('shelljs/global');
sed('-i', 'search_pattern', 'replace_pattern', file);
访问ShellJs.org了解更多示例。
答案 4 :(得分:5)
您可以在使用流读取文件时处理该文件。这就像使用缓冲区,但使用更方便的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 :(得分:1)
在用大量代码替换小占位符时遇到了问题。
我在做:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="@color/background"
android:layout_height="match_parent" >
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:contentDescription="@string/desc" />
<ProgressBar
android:id="@+id/loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
我发现问题是JavaScript的特殊替换模式,描述为here。由于我用作替换字符串的代码中有一些var replaced = original.replace('PLACEHOLDER', largeStringVar);
,因此它会使输出变得混乱。
我的解决方案是使用功能替换选项,它不做任何特殊替换:
$
答案 6 :(得分:1)
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
}
注意,仅适用于较小的文件,因为它们将被读入内存。
答案 7 :(得分:0)
我会改用双工流。像这里记录nodejs doc duplex streams
转换流是双工流,其中计算输出 从输入的某种方式。
答案 8 :(得分:0)
在Linux或Mac上,keep很简单,只需将sed与shell一起使用即可。无需外部库。以下代码可在Linux上运行。
const shell = require('child_process').execSync
shell(`sed -i "s!oldString!newString!g" ./yourFile.js`)
sed语法在Mac上略有不同。我现在无法对其进行测试,但是我相信您只需要在“ -i”之后添加一个空字符串即可:
const shell = require('child_process').execSync
shell(`sed -i "" "s!oldString!newString!g" ./yourFile.js`)
最后一个“!”之后的“ g”使sed替换一行上的所有实例。删除它,将仅替换每行的第一个匹配项。
答案 9 :(得分:0)
扩展@Sanbor的答案,最有效的方法是将原始文件作为流读取,然后还将每个块流式传输到新文件中,然后最后用新文件替换原始文件。 / p>
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);
}
})()
答案 10 :(得分:0)
npm start
<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])}`;
}, '');
}
确保您可以改进阅读模板功能,以流方式读取并逐行编写字节,以提高效率
答案 11 :(得分:0)
这可能对某人有所帮助:
这与全局替换有点不同
从我们运行的终端
%d
replace.js:
node replace.js
这就是它的作用。 我们有几个文件包含 xml:includes
但是在开发过程中,我们需要向下移动一个级别的路径。
从这里
function processFile(inputFile, repString = "../") {
var fs = require('fs'),
readline = require('readline'),
instream = fs.createReadStream(inputFile),
outstream = new (require('stream'))(),
rl = readline.createInterface(instream, outstream);
formatted = '';
const regex = /<xsl:include href="([^"]*)" \/>$/gm;
rl.on('line', function (line) {
let url = '';
let m;
while ((m = regex.exec(line)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
url = m[1];
}
let re = new RegExp('^.* <xsl:include href="(.*?)" \/>.*$', 'gm');
formatted += line.replace(re, `\t<xsl:include href="${repString}${url}" />`);
formatted += "\n";
});
rl.on('close', function (line) {
fs.writeFile(inputFile, formatted, 'utf8', function (err) {
if (err) return console.log(err);
});
});
}
// path is relative to where your running the command from
processFile('build/some.xslt');
到这里
<xsl:include href="common/some.xslt" />
所以我们最终运行了两种regx模式,一种用于获取href,另一种用于写入 可能有更好的方法来做到这一点,但它现在有效。
谢谢