2015-11-19 3 views
1

Я хочу удалить каждое событие "*", но игнорировать "**", так, например, если у меня было "testing *single star* and **double star**", предложение после удаления было бы "testing single star and **double star**".Есть ли способ заменить подстроку в зависимости от количества вхождений?

Я думал об использовании replace("*", ""), но когда я попробовал это, он избавился от всех звезд.

Что мне делать?

+1

Должны ли мы рассматривать ввод с 3 звездами? Если да, то как бы вы хотели справиться с ними? – Pshemo

+0

@Pshemo 3 звезды не нужно учитывать, но ответ Стробижева, похоже, работает во всех случаях. – silverAndroid

ответ

7

Вы можете использовать lookarounds

String s = "testing *single star* and **double star**".replaceAll("(?<![*])[*](?![*])", ""); 

См IDEONE demo (результата: testing single star and **double star**)

Ввод * в класс символов позволяет соответствовать буквальной звездочке без побега.

(?<![*]) - отрицательный lookbehind, проверяющий, нет ли звездочки перед звездочкой, а (?![*]) - это негативный взгляд, гарантирующий отсутствие звездочки после сопоставления звездочки.

3

Вы могли бы попробовать с

yourString = yourString.replaceAll("(\\*{2})|\\*","$1"); 

Объяснение: replaceAll использует регулярные механизмы (регулярное выражение) выражение. Также * является специальным символом в регулярном выражении, поэтому нам нужно его избежать (я использовал \\*, чтобы сделать это, но вы также можете использовать [*] или окружить его \\Q\\E). Теперь давайте посмотрим, что это регулярное выражение:

  • (\\*{2}) - будет пытаться соответствовать ** и поместить его в 1-й группе
  • | - ИЛИ оператора
  • \\* - матч только один *

Так это решение попытается сначала найти **, сохранить его в группе 1, а затем заменить его совпадением с группой 1 (поэтому мы заменяем его самим, что означает, что они останутся в тексте).
Но если regex engine не сможет найти ** и вместо этого найдет *, группа 1 будет пуста, так как она может совпадать только с двумя звездами (так как эта часть регулярного выражения окружена скобками). Поэтому наша замена $1 будет представлять пустую строку, что означает, что мы удалим сингл *.

Так текущее решение вызовет следующие изменения:

*  ->  - found 1 star (remove it) 
** -> ** - found 2 stars (stay) 
*** -> ** - found 2 stars (stay), 1 star (remove) 
**** -> **** - found 2 stars (stay), 2 stars (stay) 
***** -> **** - found 2 stars (stay), 2 stars (stay) and 1 star (remove) 

Если вы не хотите, чтобы повлиять на 2 или больше звезд (как *** все равно должен быть ***) вместо {2} использования {2,}, это будет позволяют нам хранить в группе 1 две или более звезд (но не одного).

+0

Я думаю, вы можете описать этот подход как «захват нечетной звездочки» (таким образом, 1 превращается в 0, 2 и 3 в 2, 4 и 5 в 4 и т. Д.). Mine немного отличается, поскольку он удаляет только 1-звездочные последовательности, заключенные с символами без звездочки. В любом случае, спортивное мастерство - это то, что я за собой :) –

+0

@stribizhev Да, * нечетно * или с изменением, описанным в конце моего сообщения * более 2 * :) – Pshemo

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