Globally replace text in several files: Difference between revisions
→{{header|C}}: incorrect tag |
→{{header|C}}: replaced incorrect code |
||
Line 14:
=={{header|C}}==
<lang C>#include <stdio.h>
#include <
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <err.h>
#include <string.h>
char * find_match(char *buf, char * buf_end, char *pat, size_t len)
char*ri="Goodbye London!",*ro="Hello New York!";▼
{
ptrdiff_t i;
char *start = buf;
while (start + len < buf_end) {
for (i = 0; i < len; i++)
if (start[i] != pat[i]) break;
if (i == len) return start;
start++;
}▼
return 0;▼
}
int replace(char *
{
int x;▼
#define bail(msg) { warn(msg" '%s'", fname); goto done; }
struct stat st;
char *buf = 0, *start, *end;
int fd = open(fname, O_RDWR);
if (fd == -1) bail("Can't open");
if (fstat(fd, &st) == -1) bail("Can't stat");
if (!
if (read(fd, buf, st.st_size) != st.st_size) bail("Bad read");
start = buf;
end = find_match(start, buf + st.st_size, from, len);
if (!end) goto done; /* no match found, don't change file */
▲ int sl=strlen(s)+1,bl=strlen(b);
▲ int oa=0,ob=0;
▲ }
ftruncate(fd, 0);
lseek(fd, 0, 0);
do {
write(fd, start, end - start); /* write content before match */
write(fd, to, nlen); /* write replacement of match */
start = end + len; /* skip to end of match */
/* find match again */
end = find_match(start, buf + st.st_size, from, len);
} while (end);
/* write leftover after last match */
if (start < buf + st.st_size)
write(fd, start, buf + st.st_size - start);
done:
if (fd != -1) close(fd);
if (buf) free(buf);
}
int main(
{
▲ return 0;
char *to = "Hello, New York!";
char * files[] = { "test1.txt", "test2.txt", "test3.txt" };
for (i = 0; i < sizeof(files)/sizeof(char*); i++)
replace(from, to, files[i]);
return 0;
}</lang>
|
Revision as of 16:05, 2 July 2011
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
You are encouraged to solve this task according to the task description, using any language you may know.
The task is to replace every occuring instance of a piece of text in a group of text files with another one. For this task we want to replace the text "Goodbye London!" with "Hello New York!" for a list of files.
AutoHotkey
<lang AutoHotkey>SetWorkingDir %A_ScriptDir% ; Change the working directory to the script's location listFiles := "a.txt|b.txt|c.txt" ; Define a list of files in the current working directory loop, Parse, listFiles, | { ; The above parses the list based on the | character fileread, contents, %A_LoopField% ; Read the file fileDelete, %A_LoopField% ; Delete the file stringReplace, contents, contents, Goodbye London!, Hello New York!, All ; replace all occurrences fileAppend, %contents%, %A_LoopField% ; Re-create the file with new contents } </lang>
C
<lang C>#include <stdio.h>
- include <stdlib.h>
- include <stddef.h>
- include <string.h>
- include <sys/types.h>
- include <fcntl.h>
- include <sys/stat.h>
- include <unistd.h>
- include <err.h>
- include <string.h>
char * find_match(char *buf, char * buf_end, char *pat, size_t len) { ptrdiff_t i; char *start = buf; while (start + len < buf_end) { for (i = 0; i < len; i++) if (start[i] != pat[i]) break;
if (i == len) return start; start++; } return 0; }
int replace(char *from, char *to, char *fname) {
- define bail(msg) { warn(msg" '%s'", fname); goto done; }
struct stat st; int ret = 0; char *buf = 0, *start, *end; size_t len = strlen(from), nlen = strlen(to); int fd = open(fname, O_RDWR);
if (fd == -1) bail("Can't open"); if (fstat(fd, &st) == -1) bail("Can't stat"); if (!(buf = malloc(st.st_size))) bail("Can't alloc"); if (read(fd, buf, st.st_size) != st.st_size) bail("Bad read");
start = buf; end = find_match(start, buf + st.st_size, from, len); if (!end) goto done; /* no match found, don't change file */
ftruncate(fd, 0); lseek(fd, 0, 0); do { write(fd, start, end - start); /* write content before match */ write(fd, to, nlen); /* write replacement of match */ start = end + len; /* skip to end of match */ /* find match again */ end = find_match(start, buf + st.st_size, from, len); } while (end);
/* write leftover after last match */ if (start < buf + st.st_size) write(fd, start, buf + st.st_size - start);
done: if (fd != -1) close(fd); if (buf) free(buf); return ret; }
int main() { char *from = "Goodbye, London!"; char *to = "Hello, New York!"; char * files[] = { "test1.txt", "test2.txt", "test3.txt" }; int i;
for (i = 0; i < sizeof(files)/sizeof(char*); i++) replace(from, to, files[i]);
return 0; }</lang>
C++
<lang c++>#include <fstream>
- include <iterator>
- include <boost/regex.hpp>
- include <string>
- include <iostream>
int main( int argc , char *argv[ ] ) {
boost::regex to_be_replaced( "Goodbye London\\s*!" ) ; std::string replacement( "Hello New York!" ) ; for ( int i = 1 ; i < argc ; i++ ) { std::ifstream infile ( argv[ i ] ) ; if ( infile ) {
std::string filetext( (std::istreambuf_iterator<char>( infile )) , std::istreambuf_iterator<char>( ) ) ; std::string changed ( boost::regex_replace( filetext , to_be_replaced , replacement )) ; infile.close( ) ; std::ofstream outfile( argv[ i ] , std::ios_base::out | std::ios_base::trunc ) ; if ( outfile.is_open( ) ) { outfile << changed ; outfile.close( ) ; }
} else
std::cout << "Can't find file " << argv[ i ] << " !\n" ;
} return 0 ;
}</lang>
D
<lang d>import std.file, std.array;
void main() {
auto from = "Goodbye London!", to = "Hello, New York!"; foreach (fn; "a.txt b.txt c.txt".split()) { write(fn, replace(cast(string)read(fn), from, to)); }
}</lang>
Icon and Unicon
This example uses the Unicon stat function. It can be rewritten for Icon to aggregate the file in a reads loop. <lang Icon>procedure main() globalrepl("Goodbye London","Hello New York","a.txt","b.txt") # variable args for files end
procedure globalrepl(old,new,files[])
every fn := !files do
if s := reads(f := open(fn,"bu"),stat(f).size) then { writes(seek(f,1),replace(s,old,new)) close(f) } else write(&errout,"Unable to open ",fn)
end
link strings # for replace</lang>
J
If files
is a variable with the desired list of file names:
<lang j>require'strings' (1!:2~rplc&('Goodbye London!';'Hello New York!')@(1!:1))"0 files</lang>
Lua
<lang lua>filenames = { "f1.txt", "f2.txt" }
for _, fn in pairs( filenames ) do
fp = io.open( fn, "r" ) str = fp:read( "*all" ) str = string.gsub( str, "Goodbye London!", "Hello New York!" ) fp:close()
fp = io.open( fn, "w+" ) fp:write( str ) fp:close()
end</lang>
Perl
<lang bash>perl -pi -e "s/Goodbye London\!/Hello New York\!/g;" a.txt b.txt c.txt</lang>
PicoLisp
<lang PicoLisp>(for File '(a.txt b.txt c.txt)
(call 'mv File (tmp File)) (out File (in (tmp File) (while (echo "Goodbye London!") (prin "Hello New York!") ) ) ) )</lang>
PureBasic
<lang PureBasic>Procedure GRTISF(List File$(), Find$, Replace$)
Protected Line$, Out$, OutFile$, i ForEach File$() fsize=FileSize(File$()) If fsize<=0: Continue: EndIf If ReadFile(0, File$()) i=0 ; ; generate a temporary file in a safe way Repeat file$=GetTemporaryDirectory()+base$+"_"+Str(i)+".tmp" i+1 Until FileSize(file$)=-1 i=CreateFile(FileID, file$) If i ; Copy the infile to the outfile while replacing any needed text While Not Eof(0) Line$=ReadString(0) Out$=ReplaceString(Line$,Find$,Replace$) WriteString(1,Out$) Wend CloseFile(1) EndIf CloseFile(0) If i ; If we made a new file, copy it back. CopyFile(file$, File$()) DeleteFile(file$) EndIf EndIf Next
EndProcedure</lang> Implementation
NewList Xyz$() AddElement(Xyz$()): Xyz$()="C:\\a.txt" AddElement(Xyz$()): Xyz$()="C:\\b.txt" AddElement(Xyz$()): Xyz$()="D:\\c.txt" GRTISF(Xyz$(), "Goodbye London", "Hello New York")
Python
From Python docs. (Note: in-place editing is not supported on Windows 8.3 operating systems).
<lang python>import fileinput
for line in fileinput.input(inplace=True):
print(line.replace('Goodbye London!', 'Hello New York!'), end=)
</lang>
Ruby
Like Perl:
ruby -pi -e "gsub('Goodbye London!', 'Hello New York!')" a.txt b.txt c.txt
Tcl
<lang tcl>package require Tcl 8.5 package require fileutil
- Parameters to the replacement
set from "Goodbye London!" set to "Hello New York!"
- Which files to replace
set fileList [list a.txt b.txt c.txt]
- Make a command fragment that performs the replacement on a supplied string
set replacementCmd [list string map [list $from $to]]
- Apply the replacement to the contents of each file
foreach filename $fileList {
fileutil::updateInPlace $filename $replacementCmd
}</lang>
TUSCRIPT
<lang tuscript> $$ MODE TUSCRIPT files="a.txt'b.txt'c.txt"
BUILD S_TABLE search = ":Goodbye London!:"
LOOP file=files
ERROR/STOP OPEN (file,WRITE,-std-) ERROR/STOP CREATE ("scratch",FDF-o,-std-) ACCESS q: READ/STREAM/RECORDS/UTF8 $file s,aken+text/search+eken ACCESS s: WRITE/ERASE/STREAM/UTF8 "scratch" s,aken+text+eken LOOP READ/EXIT q IF (text.ct.search) SET text="Hello New York!" WRITE/ADJUST s ENDLOOP ENDACCESS/PRINT q ENDACCESS/PRINT s ERROR/STOP COPY ("scratch",file) ERROR/STOP CLOSE (file)
ENDLOOP ERROR/STOP DELETE ("scratch") </lang>