नोड्ज के साथ एक फ़ाइल में एक स्ट्रिंग बदलें


167

मैं MD5 फ़ाइल नाम उत्पन्न करने के लिए md5 ग्रंट कार्य का उपयोग करता हूं । अब मैं कार्य के कॉलबैक में नए फ़ाइलनाम के साथ HTML फ़ाइल में स्रोतों का नाम बदलना चाहता हूं। मुझे आश्चर्य है कि ऐसा करने का सबसे आसान तरीका क्या है।


1
काश एक रेनमर और रिप्ले-इन-फाइल कॉम्बिनेशन होता, जो दोनों फाइल्स को रीनेम कर देता, और उन फाइल्स के लिए किसी भी रेफरेंस को सर्च / रिप्लेस कर देता।
ब्रेन 2000

जवाबों:


303

आप सरल regex का उपयोग कर सकते हैं:

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

ज़रूर, लेकिन क्या मुझे पाठ को बदलने के लिए फ़ाइल को पढ़ना है और फिर फ़ाइल को फिर से लिखना है, या एक आसान तरीका है, क्षमा करें मैं एक फ्रंटेंड लड़के से अधिक हूं।
एंड्रियास कोबरले

शायद इसे प्राप्त करने के लिए एक नोड मॉड्यूल है, लेकिन मुझे इसकी जानकारी नहीं है। एक पूर्ण उदाहरण btw जोड़ा।
असगथ

4
@Zax: धन्यवाद, मुझे आश्चर्य है कि यह 'बग' इतनी देर तक जीवित रह सकता है;)
'20:

1
माफ करना, क्योंकि मैं जानता हूं कि यूटीएफ -8 कई भाषाओं का समर्थन करता है जैसे:
डेटाबेस

यदि आपका तार आपके पाठ में कई बार दिखाई देता है, तो यह केवल पहली स्ट्रिंग को बदल देगा।
13:11 पर eltongonc

79

चूंकि प्रतिस्थापन मेरे लिए काम नहीं कर रहा था, इसलिए मैंने एक सरल या एक से अधिक फाइलों में टेक्स्ट को बदलने के लिए एक साधारण एनपीएम पैकेज रिप्ले -इन-फाइल बनाया है। यह आंशिक रूप से @ asgoth के उत्तर पर आधारित है।

संपादित करें (3 अक्टूबर 2016) : पैकेज अब वादे और ग्लब्स का समर्थन करता है, और इसे दर्शाने के लिए उपयोग के निर्देशों को अपडेट किया गया है।

संपादित करें (16 मार्च 2018) : पैकेज को अब 100k मासिक डाउनलोड से अधिक प्राप्त किया गया है और अतिरिक्त सुविधाओं के साथ-साथ सीएलआई उपकरण के साथ बढ़ाया गया है।

इंस्टॉल:

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

3
मोड़-कुंजी मॉड्यूल का उपयोग करने के लिए महान और आसान। इसे async / वेट और एक ग्लोब के साथ काफी बड़े फोल्डर में इस्तेमाल किया गया था और यह काफी तेज़ था
मैट फ्लेचर

क्या यह फ़ाइल साइज़ के साथ अधिक से अधिक काम करने में सक्षम होगा, 256 एमबी जब से मैंने कहीं पढ़ा है कि नोड js में स्ट्रिंग की सीमा 256 एमबी है
अलनी128128

मेरा मानना ​​है कि यह होगा, लेकिन बड़ी फ़ाइलों के लिए स्ट्रीमिंग प्रतिस्थापन को लागू करने के लिए प्रगति में भी एक काम है।
एडम रीस

1
इससे पहले कि मैं कभी इस एसओ उत्तर को पढ़ूं, अच्छा है, मैंने इस पैकेज (इसके सीएलआई टूल के लिए) का इस्तेमाल किया। इसे प्यार करें
रसेल चिशोल्म

38

शायद "बदलें" मॉड्यूल ( 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,
});

क्या आप जानते हैं कि पथों में फ़ाइल एक्सटेंशन द्वारा कैसे फ़िल्टर किया जा सकता है? पथों की तरह कुछ: ['पथ / से / आपकी / फ़ाइल / *। js'] -> यह काम नहीं करता है
Kalamarico

आप नोड पैटर्न का विस्तार करने के लिए ग्लोब पैटर्न का उपयोग कर सकते हैं, और फिर उन पर पुनरावृति कर सकते हैं।
रॉब

3
यह अच्छा है, लेकिन इसे छोड़ दिया गया है। यदि आप आउट-ऑफ-द-बॉक्स समाधान चाहते हैं, तो एक स्थिर पैकेज के लिए stackoverflow.com/a/31040890/1825390 देखें ।
xavdid

1
नोड-रिप्लेसमेंट नामक एक अनुरक्षित संस्करण भी है ; हालाँकि, कोड बेस को न तो यह देख रहा है और न ही इन-फाइल इन- टेक्स्ट वास्तव में फाइल में टेक्स्ट को प्रतिस्थापित करता है, वे उपयोग करते हैं readFile()और writeFile()स्वीकृत उत्तर की तरह।
c1moore

26

आप 'sed' फंक्शन का भी उपयोग कर सकते हैं जो ShellJS का हिस्सा है ...

 $ npm install [-g] shelljs


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

अधिक उदाहरणों के लिए ShellJs.org पर जाएं ।


यह सबसे साफ समाधान लगता है :)
येरकेन

1
shxआपको npm स्क्रिप्ट से चलाने की अनुमति देता है, ShellJs.org ने इसकी सिफारिश की। github.com/shelljs/shx
जोशुआ रॉबिन्सन

मुझे भी यह पसंद है। एनपीएम-मॉड्यूल की तुलना में एक ऑनलाइनर बेहतर है, लेकिन कोड की surveral लाइनें ^ ^
suther

तृतीय पक्ष निर्भरता को आयात करना सबसे साफ समाधान नहीं है।
४४३

यह मल्टीलाइन नहीं करेगा।
चॉबी

5

आप धाराओं का उपयोग करके पढ़े जाने के दौरान फ़ाइल को संसाधित कर सकते हैं। यह सिर्फ बफ़र्स का उपयोग करने जैसा है लेकिन अधिक सुविधाजनक एपीआई के साथ।

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

3
लेकिन ... क्या होगा अगर ठग regexpFind स्ट्रिंग को विभाजित करता है? क्या इरादा विफल नहीं होता है?
जाको कारु

यह बहुत अच्छी बात है। मुझे आश्चर्य है कि यदि bufferSizeआप उस स्ट्रिंग की तुलना में लंबे समय तक सेट कर रहे हैं जिसे आप बदल रहे हैं और अंतिम चंक को सहेज रहे हैं और उस समस्या से बच सकते हैं जिसे आप वर्तमान समस्या से बचा सकते हैं।
अभयारण्य

1
संभवत: इस स्निपेट को एक बड़ा चर बनाने के बजाय सीधे फाइलसिस्टम में संशोधित फ़ाइल लिखकर सुधार किया जाना चाहिए क्योंकि फ़ाइल उपलब्ध मेमोरी से बड़ी हो सकती है।
अभयारण्य

1

कोड के एक बड़े स्ट्रिंग के साथ एक छोटे प्लेसहोल्डर को प्रतिस्थापित करते समय मैं मुद्दों में भाग गया।

मैं कर रहा था:

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

मुझे लगा कि समस्या जावास्क्रिप्ट का विशेष प्रतिस्थापन पैटर्न है, यहां वर्णित है । चूँकि मैं कोड का उपयोग कर रहा था, क्योंकि इसमें स्ट्रिंग की जगह कुछ थी $, यह आउटपुट को गड़बड़ कर रहा था।

मेरा समाधान फ़ंक्शन प्रतिस्थापन विकल्प का उपयोग करना था, जो कोई विशेष प्रतिस्थापन नहीं करता है:

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

1

परमाणु प्रतिस्थापन के लिए अस्थायी लेखन फ़ाइल के साथ नोड 7.6 7.6 के लिए ES2017 / 8।

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
}

ध्यान दें, केवल स्मॉलिश फाइल्स के लिए क्योंकि उन्हें मेमोरी में पढ़ा जाएगा।


के लिए कोई ज़रूरत नहीं है bluebird, देशी Promiseऔर use.promisify का उपयोग करें ।
फ्रांसिस्को मेटो

1
@FranciscoMateo सच है, लेकिन 1 या 2 कार्यों से परे यह अभी भी सुपर उपयोगी है।
मैट

1

लिनक्स या मैक पर, सिम्पल सरल है और सिर्फ शेल के साथ सेड का उपयोग करें। किसी बाहरी पुस्तकालय की आवश्यकता नहीं है। निम्न कोड लिनक्स पर काम करता है।

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

मैक पर सिंटैक्स थोड़ा अलग है। मैं अभी इसका परीक्षण नहीं कर सकता, लेकिन मेरा मानना ​​है कि आपको "-i" के बाद खाली स्ट्रिंग जोड़ने की आवश्यकता है।

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

"जी" फाइनल के बाद "!" बनाता है sed एक लाइन पर सभी उदाहरणों को प्रतिस्थापित करता है। इसे निकालें, और प्रति पंक्ति केवल पहली घटना को प्रतिस्थापित किया जाएगा।


1

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

0

मैं इसके बजाय एक द्वैध प्रवाह का उपयोग करेगा। यहाँ दस्तावेज की तरह नोडज डॉक डुप्लेक्स धाराएँ

एक ट्रांसफ़ॉर्म स्ट्रीम एक डुप्लेक्स स्ट्रीम है जहाँ इनपुट से आउटपुट की गणना किसी तरह से की जाती है।


0

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

यह सुनिश्चित करने के लिए कि आप स्ट्रीम के रूप में पढ़ने के लिए रीडिंग टेम्प्लेट फ़ंक्शन को बेहतर बना सकते हैं और इसे और अधिक कुशल बनाने के लिए लाइन द्वारा बाइट्स की रचना कर सकते हैं

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.