2010-08-11 2 views
0

Для простоты допустим, что у нас есть входные строки с этим форматом:Regex заменить все вхождений данного символа, только после данного матча

*text1*|*text2* 

Итак, я хочу, чтобы оставить text1 и удалите все пробелы в text2.

Это может быть легко, если у нас не было TEXT1, простой поиск и замену, как это можно было бы сделать:

%s/\s//g 

, но в этом контексте я не знаю, что делать.

Я пытался что-то вроде:

%s/\(.*|\S*\).\(.*\)/\1\2/g 

, который работает, но удаление только первый символ, я имею в виду, это должно выполняться на одной и той же линии, один раз для каждого нарушившего пространства.

Таким образом, предпочтительным ограничением является решить это только с одним поиском и заменить. И, хотя я использовал синтаксис Vim, используйте обычный вкус выражения, с которым вам наиболее удобно отвечать, я имею в виду, может быть, вам нужна некоторая функциональность, предлагаемая только Perl.

Edit: Мое решение для Vim:

%s:\(|.*\)\@<=\s::g 
+0

'awk' может решить эту проблему за вас в кратчайшие сроки. –

+0

Вы имеете в виду, сначала анализируя «столбец» через awk, а затем используя sed или что-то еще для запуска поиска и замены только в этом столбце? Это похоже на мое фактическое решение, но я хотел бы сделать это только с регулярным выражением. – Doppelganger

+2

@ Карл Норум: Я установил awk, но он просто сидит там и ничего не делает. Или вы имели в виду программу awk? :) – ysth

ответ

3

Один из способов, в Perl:

s/(^.*\||(?=\s))\s*/$1/g 

Конечно гораздо большую эффективность можно, если вы позволяете больше, чем просто один поиск и замену ,

+0

Я сейчас читаю этот ответ на аналогичный вопрос, который я нашел только после того, как спросил мой. http://stackoverflow.com/questions/608319/regex-replace-but-only-between-two-patterns Принятый ответ использует lookaround, поэтому, возможно, ваш схож. Я еще не смотрел на поиски, поэтому я постараюсь понять ваше решение и посмотреть, работает ли оно. – Doppelganger

+0

@Doppelganger: находка на самом деле не нужна мне; 's/(^. * \\) \ s */$ 1/g' должно работать так же хорошо. Я думал, что взгляд будет делать это быстрее, но не знаю, правда ли это. – ysth

+0

Я нашел свое решение с поиском, но я все еще пытаюсь понять ваше. Я не получаю этот атом (^. * \ ||), я получаю его как угодно от начала строки до трубы, но я не понимаю, для чего нужен второй канал. – Doppelganger

3

Итак, у вас есть строка с одной трубкой (|), и вы хотите заменить только те пространства, которые не предшествуют трубе?

s/\s+(?![^|]*\|)//g 
+0

Лучше, чем мое. Или 's/\ s + (?!. *? \ |) // gs' – ysth

0

Вы можете попробовать встраивание кода Perl в регулярном выражении (с использованием синтаксиса (?{...})), который, однако, скорее экспериментальная функция, и может не работать или даже быть доступны в вашем сценарии.

Это

s/(.*?\|)(.*)(?{ $x = $2; $x =~ s:\s::g })/$1$x/ 

теоретически должна работать, но я получил "из памяти!" отказ, который можно зафиксировать путем замены «\ s» на пробел:

s/(.*?\|)(.*)(?{ $x = $2; $x =~ s: ::g })/$1$x/ 
+0

Если вы выполняете несколько подстановок, может также быть' s/(\ |. *)/(My $ x = $ 1) = ~ ! s \ s !! г, $ х/se'; no '(? {...})' необходимо. – ysth

Смежные вопросы