2013-02-14 2 views
0

Поэтому мне нужно вернуть измененную строку, где она заменяет первый экземпляр токена другим токеном при пропуске комментариев. Вот пример того, что я говорю:Как написать регулярное выражение в Java, которое будет выполнять .replaceFirst в группе, которая не находится в комментарии?

This whole quote is one big String 
-- I don't want to replace this @@ 
But I want to replace this @@! 

Будучи бывшим разработчиком .NET, я думал, что это было легко. Я бы просто сделать отрицательное назад ', как это:

(?<!--.*)@@ 

Но потом я узнал, Java не может это сделать. Поэтому, узнав, что фигурные скобки в порядке, я попытался это:

(?<!--.{0,9001})@@ 

Это не сгенерирует исключение, но это не соответствует @@ в комментарии.

Когда я тестирую это регулярное выражение с помощью тестера регулярных выражений Java, он работает так, как ожидалось. Единственное, о чем я могу думать, это то, что я использую Java 1.5. Возможно ли, что в Java 1.5 есть ошибка в его регулярном выражении? Предполагая, что это так, как я получу Java 1.5, чтобы сделать то, что я хочу, чтобы не обрезать свою строку и повторно собрать ее?

EDIT Я изменил оператор # на оператор, так как похоже, что регулярное выражение будет более сложным с двумя символами вместо одного. Я изначально не показывал, что я изменял запрос, чтобы избежать обсуждения темы на тему «Ну, вы не должны изменять запросы таким образом!» У меня есть очень веская причина для этого. Пожалуйста, не обсуждайте передовую практику изменения запроса. Спасибо

+1

Так что вы хотите заменить '' @@ в 3-м примере, а не на 2-й один? –

+0

В регулярном выражении Java вы не можете указывать длину «конечного числа» или регулярное выражение с неясной длиной на внешний вид. Некоторые языки даже ограничивают его регулярным выражением постоянной длины в look-behind. .NET - единственный, который я знаю, который поддерживает произвольный внешний вид длины. – nhahtdh

ответ

5

Здесь вам не нужно negative look-behind. Вы можете сделать это без этого.

Было бы так:

String str = "I don't want to replace this @@";  
str = str.replaceAll("^([^#].*?)@@", "$1"); 

Таким образом, он заменяет первое вхождение @@ в строку, которая не начинается с # с частью строки перед @@. Таким образом, удаляется @@. Здесь replaceAll работает, потому что он использует неохотный квантификатор - .*?. Таким образом, он автоматически остановится на первых @@.


Как правильно указал @nhahtdh в комментарии, что это может произойти сбой, если ваш комментарий в конце строки. Таким образом, вы можете использовать этот вариант:

String str = "I don't want to # replace this @@"; 
str = str.replaceAll("^([^#]*?)@@", "$1"); 

Этот продукт будет работать в любом случае. И в данном примере случае он не заменит @@, так как он является частью комментария.


Если ваш комментарий начинается двумя символами, то отрицательный класс символов не будет работать.Вы должны были бы использовать negative look-ahead так:

String str = "This whole quote @@ is one big String -- asdf @@\n" + 
      "-- I don't want to replace this @@\n" + 
      "But I want to replace this @@!"; 
str = str.replaceAll("(?m)^(((?!--).)*?)@@", "$1"); 

System.out.println(str); 

Выход:

This whole quote is one big String -- asdf @@ 
-- I don't want to replace this @@ 
But I want to replace this ! 

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

+1

Единственная проблема, которая может возникнуть в одной строке: 'некоторый текст здесь #comment @@'. Не уверен, что это может произойти. – nhahtdh

+0

@nhahtdh. Да, это будет проблемой. Посмотрим, как я могу изменить регулярное выражение. Nice catch :) –

+0

Я внес изменения в свой вопрос, так как на самом деле я использую два символа для начала комментариев, а не один. Как это изменит регулярное выражение? –

0

Вы можете использовать что-то вроде этого:

String string = "This whole quote is one big String\n" + 
       "# I don't want to replace this @@\n" + 
       "And I also # don't want to replace this @@\n" + 
       "But I want to replace this @@!\n" + 
       "But not this @@!"; 

Matcher m = 
    Pattern.compile (
     "^((?:[^@#]|@[^@]|#[^\n]*)*)@@", Pattern.MULTILINE). 
      matcher (string); 

StringBuffer result = new StringBuffer(); 
if (m.find()) 
    m.appendReplacement (result, "$1FOO"); 
m.appendTail (result); 

System.out.println (result.toString());