0

How can I replace the following string:

<value>-myValue</value>
          <value>1234</value>

And make it to be:

<value>-myValue</value>
          <value>0</value>

Please take into account that there is a line break.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Are you wondering about string replacement in general, or [replacement across multiple lines](http://stackoverflow.com/questions/16742526/how-to-search-and-replace-across-multiple-lines-with-perl)? – Paul Roub Aug 24 '15 at 21:10
  • 2
    Is it exactly 1234 or is that just representative of a digit string? Is the replacement always zero? What have you tried? – Jonathan Leffler Aug 24 '15 at 21:10
  • 4
    [It looks like you are trying to parse XML with regex.](http://stackoverflow.com/a/1732454/725418) Would you like to try [an XML parser](https://metacpan.org/pod/XML::LibXML) instead? – TLP Aug 24 '15 at 21:12
  • About replacement across multiple lines. I have tried sed '/-myValue.*/ {N; s/-myValue.*\./-myValue.*value>0 – tomasfly123 Aug 24 '15 at 21:13
  • If this is indeed XML, sed is not a good tool to process it. Consider using xmlstarlet, e.g. `xmlstarlet ed -u '//value[.="-myValue"]/following-sibling::value[1]' -v 0 filename.xml` – Wintermute Aug 24 '15 at 21:26

3 Answers3

2

If this is XML, TLP is right that an XML parser would be superior. Continuing on with your sed approach, however, consider:

$ sed '/<value>-myValue/ {N; s/<value>[[:digit:]]\+/<value>0/}' file
<value>-myValue</value>
          <value>0</value>
John1024
  • 109,961
  • 14
  • 137
  • 171
2

Script

sed -e '/<value>-myValue</,/<value>/{ /<value>[0-9][0-9]*</ s/[0-9][0-9]*/0/; }' data

From a line containing <value>-myValue< to the next line containing <value>, if the line matches <value>XX< where XX is a string of one or more digits, replace the string of digits with 0.

Input

This is not something to change
<value>-myValue</value>
          <value>1234</value>
<value>myValue</value>
          <value>1234</value>
nonsense
<value>-myValue</value>
          <value>abcd</value>
<value>-myValue</value>
          <value>4321</value>
stuffing

Output

This is not something to change
<value>-myValue</value>
          <value>0</value>
<value>myValue</value>
          <value>1234</value>
nonsense
<value>-myValue</value>
          <value>abcd</value>
<value>-myValue</value>
          <value>0</value>
stuffing
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
0

You can possibly simplify this a bit, depending on what criteria you specifically want to use:

#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;

my $twig = XML::Twig->new( 'pretty_print' => 'indented_a' )->parse( \*DATA );
foreach my $value ( $twig->findnodes('//value') ) {
    if (    $value->trimmed_text eq '-myValue'
        and $value->next_sibling('value')
        and $value->next_sibling('value')->text =~ m/^\d+$/ )
    {
        $value->next_sibling('value')->set_text('1234');

    }
}

$twig->print;

__DATA__
<root>
<value>-myValue</value>
          <value>0</value>
          </root>

This outputs:

<root>
  <value>-myValue</value>
  <value>1234</value>
</root>
  • It parses your XML.
  • Looks for all nodes with a tag of value.
  • Checks that it has a sibling.
  • Checks that sibling is 'just numeric' e.g. matching regex ^\d+$
  • replaces the content of that sibling with 1234.

And will work on XML regardless of formatting, which is the problem with XML - pretty fundamentally there's a bunch of entirely valid things you can do that are semantically identical in XML.

Sobrique
  • 52,974
  • 7
  • 60
  • 101