Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

parsing a multi-line pattern and replacing

by ghosh123 (Monk)
on Apr 24, 2014 at 18:49 UTC ( #1083668=perlquestion: print w/replies, xml ) Need Help??

ghosh123 has asked for the wisdom of the Perl Monks concerning the following question:

Hi
I am parsing a pattern '<default>any text</default>' pattern in a file and wherever found, I want to replace that by '<default>enabled</default>'.
Now the problem is the above mentioned pattern may occur in a single line and in multiple line as well. So the input file may look something like

******* inputfile****************
this is line 1
this is line 2
<default>sometext</default>
this is line 3
<default>some more text
some more in next line
</default>
this is last line
*************************************
I am trying with this, which is working when the pattern is in single line but not for multiple line. The code for multiple line tried is commented out.

use strict; use warnings; use Tie::File; my $file = "inputfile"; my @array; tie @array , 'Tie::File', $file ; my $start = '<default>'; my $end = '</default>'; my $val = 'enabled'; my $replace = $start.$val.$end; print "replace $replace \n"; for (my $i = 0 ; $i <= $#array ; $i++) { #below if block is tried for multiple line pattern but not working # if ($array[$i] =~ /^<default>/../<^\/default>/) if($array[$i] =~ /^<default>/) #this is working { $array[$i] =~ s/^<default>.*<\/default>/$replace/g; } } untie @array;

seeking help on how can it be made to match both the patterns ?

Replies are listed 'Best First'.
Re: parsing a multi-line pattern and replacing
by rjt (Curate) on Apr 24, 2014 at 19:35 UTC

    Why are you using Tie::File? Doing line-based matching will be tricky. Unless your files are huge (many megabytes), slurping the entire file will be both faster and easier, and File::Slurp save you from worrying about any temp file mechanics:

    use File::Slurp 'edit_file'; edit_file { s!<default>.+?</default>!<default>enabled</default>!sg } ' +inputfile';

    With the same inputfile you list, I get the expected output:

    this is line 1 this is line 2 <default>enabled</default> this is line 3 <default>enabled</default> this is last line

    Have a look at File::Slurp for more information on this often overlooked but very handy function.

    use strict; use warnings; omitted for brevity.

      Many thanks for your suggestion.
      You all are correct, for ease of explanation I did not mention that the inputfile is a XML file.
      Basically I have a hash which contains the tags of xml and their default values .
      Now only those tags will be replaced which has a key in the hash. So the xml inputfile actually looks like :

      **********************************
      <user>
      <default>dean</default>
      </user>
      <id>
      <default>38339</default>
      </id>
      <workarea>
      <default>/home/dean</deault>
      </workare>
      ************************************

      And lets assume the hash has 2 keys for id and workarea :

      %hash = (id => 94848, workarea=> '/home/unix' )
      So in this case while parsing the xml , I will only replace <default> values for <id> and <workarea>

        Hi,
        I could do it myself. Here goes the code

        tie @array , 'Tie::File' , "$file" ; foreach my $key (keys %varHash) { my $keyflag = 0 ; my $changedVal = $varHash{$key}{newVal}; my $startdef = '<default>'; my $enddef = '</default>'; my $storedindex; print "key $key | changedVal $changedVal \n"; for(my $i = 0 ; $i <= $#array ; $i++) { if($array[$i] =~ /$key/) { print "here $key \n"; $keyflag = 1 ; next; } elsif ($array[$i] =~ /\<default\>.*?\<\/default\>/gs) { # print "array[i] $array[$i] \n"; if($keyflag) { $array[$i] = "$startdef"."$changedVal"."$enddef"; $keyflag = 0; last; } } elsif($array[$i] =~ /^\s*\<default>.*[^\>]$/) { $storedindex = $i ; } elsif($storedindex > 0 ) { if ($array[$i] =~ /\<\/default\>/) { my $range = $i - $storedindex; splice(@array, $storedindex,$range); $array[$storedindex] = "$startdef"."$changedVal"." +$enddef"; last; } } } } untie(@array); }
Re: parsing a multi-line pattern and replacing
by InfiniteSilence (Curate) on Apr 24, 2014 at 19:41 UTC

    Here's how you would select the information you want. I'll leave it as an exercise to modify the code to replace the values.

    #!/usr/bin/perl -w use strict; my $wholefile = ''; while(<DATA>) { $wholefile .= $_; } while($wholefile=~m/\<default\>([^\>]+)\<\/default\>/gs) { print qq~$1\n~; } 1; __END__ this is line 1 this is line 2 <default>sometext</default> this is line 3 <default>some more text some more in next line </default> this is last line

    Prints...

    sometext some more text some more in next line

    Celebrate Intellectual Diversity

Re: parsing a multi-line pattern and replacing
by choroba (Archbishop) on Apr 25, 2014 at 00:35 UTC
    If your file is XML or HTML, use a proper parser. For example, XML::XSH2:
    open inputfile ; for //default set text() 'enabled' ; save :b ;
    لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: parsing a multi-line pattern and replacing
by Anonymous Monk on Apr 24, 2014 at 18:55 UTC

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1083668]
Approved by rjt
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (6)
As of 2022-05-20 15:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Do you prefer to work remotely?



    Results (73 votes). Check out past polls.

    Notices?