2012-05-14 2 views
1

Вот таблица для преобразования я хочу сделать в Regex:Как заменить все, кроме последнего повторяющегося письма в Regex?

From  To 
================ 
CAT  CAT 
EGG  EGG 
A   A 
Z   Z 
AA   ZA 
BB   ZB 
ZZ   ZZ 
AAA  ZZA 
HHHHH  ZZZZH 

Другими словами, где строка и та же буква повторяется 2 раза или больше, я хочу, чтобы заменить все буквы кроме Страшного один с Z.

Я мысленно заблокирован здесь. Это то, что я придумал до сих пор, и он не работает:

FIND:  ^(?<=\1*?)([A-Z])(?=\1+)$ 
REPLACE: Z 

Я не уверен, является ли обратная ссылка может использоваться даже перед группой захвата, но в любом случае, заменяя первый \1 с . не помогает.

Я использую C#, поэтому я ищу регулярные выражения .NET-стиля. Я мог бы, конечно, сделать это с помощью обычных манипуляций с строками, но у меня есть необходимость в использовании регулярных выражений.

+0

Почему EGG не следует заменить EZG? – m0skit0

+0

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

+2

Btw Я не думаю, что в этом случае могут применяться регулярные выражения, потому что в этом случае ваш язык не является регулярным, а не контекстом, потому что регулярное выражение должно каким-то образом знать, какой символ следует повторять, и это не является контекстом (я думаю ...). – m0skit0

ответ

3

Был ли кто-то заказан dark magic?

FIND: \G([A-Z])(?=\1) 
REPLACE: Z 

\G якоря каждый матч ЯВНО к началу строки, как \A делает, или в положение, при котором предыдущий матч завершился. Другими словами, ([A-Z]) в вашем регулярном выражении всегда пытается соответствовать самому следующему символу, и благодаря lookahead - (?=\1) - вы знаете, что следующий символ совпадает с тем, который вы только что заменили.

Кроме того, регулярное выражение в вашем собственном ответе не работает для меня. + не делает ничего полезного (в конце концов, вы заботитесь только о следующем персонаже), но и это ничего не повредит. Что заставило меня работать, я снимал $.

UPDATE: Я не понял, что строка должна быть двух или более одного и того же символа и ничего больше. Это означает, что необходимы + и $. Пока я нахожусь, я обращусь к дополнительному требованию о том, чтобы строки XX, XXX, II и III остались в покое. Вуаля!

\G(?!\A(?:XXX?|III?)$)([A-Z])(?=\1+$) 
+0

Удивительный! Мне пришлось сделать одно небольшое изменение: '\ G ([A-Z]) (? = \ 1 + $)'. Без '+ $' в lookahead оно преобразует 'HHHHG' в' ZZZHG' вместо того, чтобы оставлять его в покое (например, «EGG»). Вот где я собирался с этими '+' и '$' в моем первоначальном ответе. Видимо, мне нужно освежиться на якорях, я не использую их очень часто, кроме '^' и '$'. Одно предостережение, о котором я не упоминал, - XX, II, XXX и III должны быть исключены из этой замены в моем фактическом приложении. Поэтому, в конце концов, мне, вероятно, придется придерживаться кода замены, отличного от RegEx. – richardtallent

+0

Не сдавайтесь! Проверьте мое редактирование. –

+0

+1 Приятно, используя якорь \ G, заставляя матч, где последний остановился. Это быстрее, чем смотреть. Добавление (? = \ 1 + $) действительно завершает циркуляцию. – sln

2

Возможно, сначала нужно совместить ваш желаемый символ, а затем сделать lookahead и lookbehind, включая привязки в тех, а не в основном выражении, так как вы хотите, чтобы выражение соответствовало символу по символу.

([A-Z])(?<=^\1*)(?=\1+$) 

Это не будет очень показательно, потому что это целая цепочка для каждого персонажа.

Вам будет лучше использовать регулярное выражение, чтобы обнаружить, что строка состоит из одного и того же символа, а затем заменяет все символы, кроме последнего, на Z с помощью стандартного метода замены строки или создавая строку Zs длиной от первоначальной минусовой единицы и, например, добавление первого символа исходного.

+0

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

+0

В этом случае это не делает различий, но взгляд на опциональный '\ 1 *' кажется ошибочным. '([A-Z]) (? <=^\ 1 +) (? = \ 1 + $)' может сделать разницу в производительности, не уверен. – sln

+0

Я пошел с Аланом для более простого выражения, но +1 для рабочего ответа и по праву упомянул аспект производительности. – richardtallent

0

Возможно, что-то вроде матча, а затем замена может работать.

string [] Samps = { "CAT", "EGG", "A", "Z", "AA", "BB", "ZZ", "AAA", "HHHHH" }; 
foreach (var item in Samps) 
{ 
    string line = item + "\t\t"; 
    line += Regex.Match(item, @"^([A-Z])\1+$").Success ? 
      Regex.Replace(item, @".(?!$)", "Z") : 
      item; 
    Console.WriteLine(line); 
} 

Выход

CAT    CAT 
EGG    EGG 
A    A 
Z    Z 
AA    ZA 
BB    ZB 
ZZ    ZZ 
AAA    ZZA 
HHHHH   ZZZZH 
Смежные вопросы