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

How to set the flag and search for the first <p> tag in the file and replace with <con> and a set a flag to 0.
Again search for the last </p> tag in the file and replace with </con> and a set a flag to 0.

Replies are listed 'Best First'.
Re: Set the flag
by gmargo (Hermit) on Nov 05, 2009 at 13:41 UTC
Re: Set the flag
by cormanaz (Deacon) on Nov 05, 2009 at 13:53 UTC
    It will be something like this, which turns $flag to 1 when it finds something:
    my $foo = "This is a test."; my $flag = 0; print "$flag\t$foo\n"; $flag = ($foo =~ s/a/the/); print "$flag\t$foo\n";
    But like irah says, you need to provide some code or data if you want more specific help.
      #!/usr/bin/perl use strict; use warnings; my $flag=0; while(<DATA>){ if($flag == 0){ if($_ =~ m/<p>/){ $_ =~ s/<p>/<con>/; $flag=1; } } print $_; } __DATA__ <root> <p>This is para1</p> <p>This is para2</p> </root>
      I have tried for the matching first <p>. But in a file how to find the last </p> tag and substitute.
      Please help me on this
Re: Set the flag
by irah (Pilgrim) on Nov 05, 2009 at 13:36 UTC

    Its nice to use regular expression. It will solve easily. Further more info, see, "man perlre". I don't know what reason do you want to use flags.

    It's not the website to get the source code, First explain, what you have tried, and if you are facing any problem, ask in this forum?.

Re: Set the flag
by Capablanca (Novice) on Nov 05, 2009 at 13:49 UTC
Re: Set the flag
by gmargo (Hermit) on Nov 05, 2009 at 16:28 UTC

    The following will work even if you give it only a single line of input. The "flag" you mention is more properly referred to as a state variable.

    #!/usr/bin/perl use strict; use warnings; my $retain = ""; while (<DATA>) { chomp; if (m{^(<p>)(.*)(</p>)$}) { my ($begin, $middle, $end) = ($1, $2, $3); # This line is inside a <p>...</p> match. # Handle differently if it's the first line. if (! $retain) { # Found first <p> in block, replace with <con>. # Print beginning and middle, but retain end, in case # this one line is also the end of the block. print "<con>"."$middle"; $retain = $end; } else { print "$retain\n"; # Finish off previous line print "$begin"."$middle"; # Start new line $retain = $end; # retain ending } } else { # This line is not a <p>...</p> match, # so flush preserved output, if any, # and copy this line to the output. if ($retain) { print "</con>\n"; # Finish off previous line $retain = ""; } print "$_\n"; } } if ($retain) { print "</con>\n"; # Finish off previous line } #<p>This is para2</p> #<p>This is para3</p> __DATA__ <root> <p>This is para1</p> </root>

    Input cases and appropriate output:

    Case 1 Input: Single line

    <p>This is para1</p>

    Case 1 Output:

    <con>This is para1</con>

    Case 2 Input: Multiple lines in block

    <p>This is para1</p> <p>This is para2</p> <p>This is para3</p>

    Case 2 Output:

    <con>This is para1</p> <p>This is para2</p> <p>This is para3</con>

    Case 3 Input: non match lines present

    <root> <p>This is para1</p> <p>This is para2</p> </root>

    Case 3 Output:

    <root> <con>This is para1</p> <p>This is para2</con> </root>

    Case 4 Input: Multiple separate blocks (I assume you want separate blocks treated separately.)

    <root> <p>This is para1</p> <p>This is para2</p> </root> <stem> <p>This is para3</p> </stem>

    Case 4 Output:

    <root> <con>This is para1</p> <p>This is para2</con> </root> <stem> <con>This is para3</con> </stem>

      The file contains so many lines other than <p> tags.
      How to use substitute function to replace
      s/<p>/<con><p>/;
      When the first

      tag is found. and substitute

      s/<\/p>/<\/con><\/p>/;
      for the last </p> tag in the file

        Now you're changing the spec!

        I gave you four cases of input above. Why don't you show me the four cases of output that you expect.

      Thanks for the answer. But I need some help using substitution.
      Please help me. I am new to perl. I tried my level best but no luck.
      Even i flag concept did'nt work as it does'nt work for the continuous files when placed below the code.
Re: Set the flag
by ikegami (Patriarch) on Nov 05, 2009 at 20:43 UTC
    $flag1 = 1; $flag2 = 0; $flag3 = 0; s{<p>}{<con>}; s{.*\K</p>}{</con>}s; # Faster, Perl >= 5.10 s{(.*)</p>}{$1</con>}s; # Slower, any Perl
      The above code is replacing every <p> with <con>.
      I have to replace only in the first <p> and skip replacing of <con> for other <p> tag.
      The replacement should work only for the first <p> tag in a file and I have to replace only in the last </p> and skip replacing of </con> for other </p> tag.
      The replacement should work only for the last </p> tag in a file Please help me on this.

        The above code is replacing every <p> with <con>.

        No, just the first. You'd need to add /g to make it replace every instance.

        You said you needed to search the file. You aren't searching every line, right?

Re: Set the flag
by Marshall (Canon) on Nov 05, 2009 at 16:48 UTC
    I think that you have multiple errors in your spec.
    1. Often <p> and </p> tags occur in pairs. But not always, this mark up for example has no </p>'s in it.
    2. Your "flag" spec is probably wrong as there is no way for it to be set to anything other than "0".

    Maybe you mean to insert a <con> tag before the first <p> and a </con> after the last </p>?
    The way your spec is written, you may wind up with unmatched <p> and </p> pairs.

    I would show a real example (short as you can be that demo's the problem) and your current code.

      In this input below:, I want to substitute <p> tag
      <root> <id>274660P4</id> <p>This is para1</p> <p>This is para2</p> <date>Wednesday, October 28, 2009</date> </root>
      The output:
      <root> <id>274660P4</id> <con><p>This is para1</p> <p>This is para2</p> <p>This is para3</p> <p>This is para4</p> <p>This is para5</p><con> <DD>Wednesday, October 28, 2009</DD> </root>
      Please help how to write the regular expression, to substitute for first and last p tag.
        Wild stab in the dark.
        #!usr/bin/perl use strict; use warnings; my $input = do{local $/; <DATA>}; $input =~ s|(<p>)|<con>\n$1|; $input =~ s|(.*</p>)|$1\n</con>|s; print $input; __DATA__ <root> <p>This is para1</p> <p>This is para2</p> <date>Wednesday, October 28, 2009</date> </root>
        <root> <con> <p>This is para1</p> <p>This is para2</p> </con> <date>Wednesday, October 28, 2009</date> </root>
Re: Set the flag
by ambrus (Abbot) on Nov 06, 2009 at 12:58 UTC