2013-01-05 13 views

Odpowiedz

148

Można użyć prostego wyrażenia regularnego:

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

więc ...

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

Oczywiście, ale czy muszę przeczytać plik, zastąpić tekst, a następnie napisać plik ponownie, czy jest łatwiejszy sposób, przepraszam, że jestem bardziej facetem z frontendu. –

+0

Być może istnieje moduł węzła, aby to osiągnąć, ale nie jestem tego świadomy. Dodano pełny przykład btw. – asgoth

+2

mały błąd, zamień na linię 6 'someFile' z 'danymi' – Zax

20

Można również użyć funkcji 'sed', który jest częścią ShellJS ...

$ npm install [-g] shelljs 


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

Odwiedź stronę ShellJs.org, aby uzyskać więcej przykładów.

+0

to wydaje się być najczystszym rozwiązaniem :) – Yerken

+1

'shx' pozwala na uruchamianie skryptów npm, zalecane przez firmę ShellJs.org. https://github.com/shelljs/shx –

+0

Podoba mi się też. Lepszy oneliner, niż moduł npm, ale kilka linii kodu ^^ – suther

24

Być może moduł "zamień" (www.npmjs.org/package/replace) również będzie działał dla Ciebie. Nie wymagałoby to odczytywania, a następnie zapisywania pliku.

Adaptacja dokumentacji:

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

Czy wiesz, jak filtrować według rozszerzenia pliku w ścieżkach? coś w rodzaju ścieżek: ['ścieżka/do/twój/plik/*. js'] -> to nie działa – Kalamarico

+0

Możesz użyć węzła-glob, aby rozwinąć wzorce globu do tablicy ścieżek, a następnie iterować nad nimi. – RobW

+2

To jest ładne, ale zostało porzucone. Zobacz http://stackoverflow.com/a/31040890/1825390 dla pakietu konserwacyjnego, jeśli chcesz mieć gotowe rozwiązanie. – xavdid

24

Od zastąpić nie działa dla mnie, stworzyliśmy prosty pakiet npm replace-in-file szybko zamienić tekst w jednej lub kilku plików. Częściowo opiera się na odpowiedzi @ asgotha.

Edytuj (3 października 2016 r.): Pakiet obsługuje teraz obietnice i globsy, a instrukcje użytkowania zostały zaktualizowane, aby to odzwierciedlić.

Instalacja:

npm install replace-in-file 

Wymaga modułu

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

Określ opcje zamienne

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

wymiana asynchroniczny z obietnic:

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

wymiana asynchroniczny z zwrotnego:

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

synchroniczna wymiana:

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

Można przetworzyć pliku podczas odczytywania za pomocą strumieni. To tak, jak przy użyciu buforów, ale z wygodniejszym interfejsem 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'); 
+1

Ale ... co jeśli fragment dzieli ciąg regexpFind? Czy zatem nie ma zamiaru? –

+0

To bardzo dobry punkt. Zastanawiam się, czy ustawiając 'bufferSize' dłuższą niż ciąg, który zastępujesz i zapisując ostatni fragment i łącząc się z bieżącym, możesz uniknąć tego problemu. – sanbor

+0

Prawdopodobnie ten fragment kodu powinien zostać poprawiony poprzez zapisanie zmodyfikowanego pliku bezpośrednio do systemu plików, zamiast tworzenia dużej zmiennej, ponieważ plik może być większy niż dostępna pamięć. – sanbor

0

użyłbym strumień dwustronnego zamiast. jak udokumentowane nodejs doc duplex streams

transformacji strumień jest strumieniem dupleksu w którym wyjście jest obliczana w jakiś sposób z wejścia.

1

Wystąpił problem przy wymianie małego symbolu zastępczego z dużym ciągiem kodu.

robiłem:

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

zorientowali się problemem było specjalne wzory zamienne Javascript w opisany here. Ponieważ kod, który użyłem jako zastępujący ciąg znaków, miał w sobie pewną liczbę $, zepsuł wynik.

Moje rozwiązanie było użyć opcji zastępczej funkcja, która nie robi żadnej specjalnej Zamiennik:

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

ES2017/8 dla węzła 7.6+ z pliku tymczasowego zapisu dla wymiany atomowej.

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 
} 

Uwaga, tylko dla małych plików, ponieważ będą one odczytywane do pamięci.

+0

Nie trzeba używać "bluebird", używać natywnych 'Promise' i [util.promisify] (https://nodejs.org/dist/latest-v8.x/docs/api/util.html#util_util_promisify_original). –

+0

@FranciscoMateo Prawda, ale poza 1 lub 2 funkcjami promisifyWszystko jest nadal bardzo przydatne. – Matt