问题
I want to do multi-line string replacements in some template files, but retain a pretty indentation.
Here's an example of the template:
<TAG1>
<TAG2>
%REPLACETHIS%
</TAG2>
</TAG1>
Now, when I simply replace the string %REPLACETHIS% with a string like
<REPLACEDSTRINGTAG1>
replacedstringtext
</REPLACEDSTRINGTAG1>
it will look something like:
<TAG1>
<TAG2>
<REPLACEDSTRINGTAG1>
replacedstringtext
</REPLACEDSTRINGTAG1>
</TAG2>
</TAG1>
when it should look like:
<TAG1>
<TAG2>
<REPLACEDSTRINGTAG1>
replacedstringtext
</REPLACEDSTRINGTAG1>
</TAG2>
</TAG1>
It gets even more complicated because the template will be part of a bigger template where it should be indented correctly as well.
I'm trying to achieve this in Perl, but basically the problem is the same in all the languages I know.
Has anyone a better idea than to just replace line-by-line with variables that keep track of the current indent depth? Which is very cumbersome due to the multi-level-template structure.
Basically, what I need is a substitute for a simple regex that will not only put the first line of the substitution string at the right column, but puts every line on that column. So if %REPLACETHIS% is at column 10, all the lines in the replacement string should be put at col 10... maybe there is some tricky built-in magic with regexes in Perl?
回答1:
Now that your template files are in XML format, you could use some XML processing modules to handle it. It's more flexible and reliable.
For your case, XML::LibXML could handle perfectly:
use XML::LibXML;
use XML::LibXML::PrettyPrint;
my $xml = "template.xml";
my $parser = XML::LibXML->new();
my $tree = $parser->parse_file($xml);
my $root = $tree->getDocumentElement;
my ($replace_node) = $root->findnodes('/TAG1/TAG2');
$replace_node->removeChildNodes();
my $new_node = $tree->createElement('REPLACEDSTRINGTAG1');
$new_node->appendText('replacedstringtext');
$replace_node->addChild($new_node);
my $pp = XML::LibXML::PrettyPrint->new(indent_string => "\t");
$pp->pretty_print($tree);
print $tree->toString;
回答2:
Not convinced regex is the correct approach for this, however if you use a group to capture the indentation before %REPLACETHIS%
, you can just enter it back into the subsitution.
e.g.
s/(.*)%REPLACTHIS%/$1<REPLACEDSTRINGTAG1>\n$1 replacedstringtext\n$1</REPLACEDSTRINGTAG1>
DEMO
来源:https://stackoverflow.com/questions/25501949/multiline-string-replace-with-pretty-indentation