Multiple search/replace text patterns in one go

Hi,

I need to replace different patterns in a text file, kind of a batch search/replace, and the patterns should be saved and editable to use in other occasions.

For example, an application that would read a pattern file like this:


"0,01" "0.01"
"0,02" "0.02"
"x y" "X-Y"
...

So a text file like this

x y 0,01 0,02 z 0.00 

would be changed to

X-Y 0.01 0.02 z 0.00 

I want to be able to reuse the pattern file, with eventual edits, in other text files. This doesn’t need to change multiple text files, just one each time.

I’ve looked at Alt. Find & Replace extension to libreoffice writer but it’s not obvious how to create batch files, the examples given are quite complex.

Any suggestions for an easy GUI or bash script?

Thanks.

This looks like a job for “sed” (stream editor). Maybe try:

man sed

Hmm, the learning curve might be a bit steep, but you can probably google for example of using “sed”.

My rough draft for a Ruby-based script (I call it »substpatn.rb«):


#!/usr/bin/ruby -w
# vim:ai:nu:et:sta:sts=4:sw=4

patterns = {
    "0,01" => "0.01",
    "0,02" => "0.02",
    "x y"  => "X-Y", 
}

infile  =  ARGV[0]
outfile =  File.open(infile + '.out', 'w')

File.open(infile).each_line do |line|
    patterns.each { |k,v| line.gsub!(k,v) }
    outfile.write line
end

outfile.close

Example session:

▶ cat **test.text
**x y 0,01 0,02 z 0.00
x y 0-01 0,02 z 0.00
X y 0,01 0,02 z 0.00
▶ ruby -w substpatn.rb test.text *# reads **test.text** and saves substituted output in **test.text.out***
▶ cat **test.text.out** 
X-Y 0.01 0.02 z 0.00
X-Y 0-01 0.02 z 0.00
X y 0.01 0.02 z 0.00
▶ _

For ease of testing I put the replacement rules in a hash (patterns above), but this hash could also be constructed from parsing an externel file containing the replacement rules.
What do you guys think?

Addendum: come to think of it, it would be tedious to list rules for each decimal number between »0,00« and »9,99« just to replace the decimal comma with a point. That’s why this version…

#!/usr/bin/ruby -w
# vim:ai:nu:et:sta:sts=4:sw=4

patterns = { 
    'x y'  => 'X-Y', *# rules for decimal numbers see below*
}

infile  =  ARGV[0]
outfile =  File.open(infile + '.out', 'w')

File.open(infile).each_line do |line|
    patterns.each { |k,v| line.gsub!(k,v) }
    line.gsub!(**/(\d+).,](\d+)/, '\1.\2'**) *# enforce a period/point/dot in all decimal numbers*
    outfile.write line
end

outfile.close

… does the conversion in a seperate line (the one beginning with »line.gsub!«).

»(\d+)« means: match one or more decimal digits and save them for later; ».,]« means dot or comma, and »\1.\2« tells Ruby to use the previously matched digits from the first and second pairs of parentheses and insert these digits into the resulting string, seperated by a ».«.

(This may appear ugly and like line noise, but once understood — and syntax-highlighted appropriately with a good editor —, its usefulness only grows and grows. It has for me.)

Let’s see what this little scriptlet does:

▶ cat test.text
x y 0,01 2,34 z 5.67
x y 0,89 0.12 z 0.34
X y 5,67 8,90 z 1.00
▶ ruby -w substpatn.rb test.text 
▶ cat test.text.out 
X-Y 0.01 2.34 z 5.67
X-Y 0.89 0.12 z 0.34
X y 5.67 8.90 z 1.00
▶ _

Parsing this kind of coordinates (?) line by line can be done as lax or as strict as desired. For example, the »X y« in the third line remains untouched because Ruby performs the replacements case-sensitively. Don’t hesitate to reply if you have questions or ideas for any additional features.

Thank you very very much, unix 111!

Worked like a charm, exactly what I wanted.

Best regards,

Bruno