2016-12-18 2 views
0

У меня есть документ XML с текстом в значениях атрибута. Я не могу изменить способ создания XML-файла, но вам нужно извлечь значения атрибута без потери \ r \ n. Парсер XML, конечно же, вытесняет их.Заменить строки только в пределах регулярного выражения в perl

Так что я пытаюсь заменить \ r \ n в значениях атрибутов ссылками на сущности Я использую perl для этого, потому что это не-жадное соответствие. Но мне нужна помощь, чтобы замена произошла только в матче. Или мне нужно более простой способ сделать это :)

Вот то, что я до сих пор:

perl -i -pe 'BEGIN{undef $/;} s/m_description="(.*?)"/m_description="$1"/smg' tmp.xml 

Это соответствует тому, что мне нужно работать: (. *). Но я не знаю, как развернуть этот шаблон, чтобы соответствовать ему внутри, и выполнять замену в результатах. Если бы я знал, сколько я мог бы сделать, но мне кажется, что мне нужно переменное количество групп захвата или что-то в этом роде? Для регулярного выражения много чего не понимаю, и кажется, что что-то нужно делать.

Пример:

preceding lines 
stuff m_description="Over 
any number 
of lines" other stuff 
more lines 

должны пойти:

preceding lines 
stuff m_description="Over
any number
of lines" other stuff 
more lines 

Решение

Благодаря Ikegam и ysth для решения я использовал, что для 5.14+ является:

perl -i -0777 -pe's/m_description="\K(.*?)(?=")/ $1 =~ s!\n!
!gr =~ s!\r!
!gr /sge' tmp.xml 
+1

показать образец данных? то, что вы показываете, не является XML – ysth

+0

Вероятно, вы хотите что-то вроде 'perl -i -p0e '/ m_description =" \ K ([^ "] *)/$ 1 = ~ s% \ r \ n% % gr/ge'' ('-0' примерно совпадает с' BEGIN {undef $ /} '). – Dada

+0

Думаю, вам нужна свернутая копия спецификации XML для prod. Почти как XML, но не совсем довольно грязный. Перла один лайнер будет трудно читать. Написание его как скрипта, в котором вы извлекаете и переформатировать описание, будет проще. – Sobrique

ответ

2

. должен соответствовать \n (поскольку вы указываете флаг /s) и \r.

Для замены в результатах, используйте /e:

perl -i -0777 -pe's/(?<=m_description=")(.*?)(?=")/ my $replacement=$1; $replacement=~s!\n!&#10;!g; $replacement=~s!\r!&#13;!g; $replacement /sge' tmp.xml 

Я также изменил его использовать/предпросмотр просмотра назад, чтобы сделать код более простым и использовать -0777 установить $/ в режим чавкать и для удаления бесполезных /m.

+0

'm_description =" \ K' является более эффективным и менее шумным, чем '(? <= M_description =") '. Требуется 5.10 + – ikegami

+1

'my $ replacement = $ 1; $ Замена = ~ s! \ П! ! G; $ Замена = ~ s! \ Г! ! G; $ replacement' также может быть записана как '$ 1 = ~ s! \ n! ! Gr = ~ s! \ R! ! Gr' если у вас есть 5.14+ – ikegami

+0

какой ikegami сказал. Я был слишком ленив, чтобы найти эти две требуемые версии perl. – ysth

0

ОК, поэтому, хотя это выглядит как проблема XML, это не так. Проблема XML - это человек, создающий ее. Вероятно, вы должны дать им prod с свернутой копией спецификации в качестве вашего первого порта для «фиксации» этого.

Но в противном случае - я бы сделал подход с двумя проходами, где я прочитал текст, найду все «капли», соответствующие описанию, а затем заменим их все.

Что-то вроде этого:

#!/usr/bin/env perl 

use strict; 
use warnings; 

use Data::Dumper; 

my $text = do { local $/ ; <DATA> }; 

#filter text for 'description' text: 
my @matches = $text =~ m{m_description=\"([^\"]+)\"}gms; 

print Dumper \@matches; 

#Generate a search-and-replace hash 
my %replace = map { $_ => s/[\r\n]+/&#13;&#10;/gr } @matches; 
print Dumper \%replace; 

#turn the keys of that hash into a search regex 
my $search = join ("|", keys %replace); 
    $search = qr/\"($search)\"/ms; 

print "Using search regex: $search\n"; 
#search and replace text block 
$text =~ s/m_description=$search/m_description="$replace{$1}"/mgs; 

print "New text:\n"; 
print $text; 

__DATA__ 
preceding lines 
stuff m_description="Over 
any number 
of lines" other stuff 
more lines 
Смежные вопросы