2016-08-31 4 views
1

я соединял эту упрощенную версию моего кода, чтобы продемонстрировать вопрос:Java Regex для фильтрации строк с комментариями не работает, как ожидалось

public static void main(String []args){ 
    String content="1 [thing i want]\n" + 
    "2 [thing i dont want]\n" + 
    "3 [thing i dont want] [thing i want]\n" + 
    "4 // [thing i want]\n" + 
    "5 [thing i want] // [thing i want]\n"; 

    String BASE_REGEX = "(?!//)\\[%s\\]"; 
    Pattern myRegex = Pattern.compile(String.format(BASE_REGEX, "thing i want")); 
    Matcher m= myRegex.matcher(content); 
    System.out.println("match? "+m); 
    String newContent = m.replaceAll("best thing ever"); 
    System.out.println("regex "+myRegex); 
    System.out.println("content:\n"+content); 
    System.out.println("new content:\n"+newContent); 
} 

я ожидаю мой выход будет:

new content: 
1 best thing ever 
2 [thing i dont want] 
3 [thing i dont want] best thing ever 
4 // [thing i want] 
5 best thing ever // [thing i want] 

но Я вижу:

new content: 
1 best thing ever 
2 [thing i dont want] 
3 [thing i dont want] best thing ever 
4 // best thing ever 
5 best thing ever // best thing ever 

Как исправить регулярное выражение?

Неизмененная строка:

content: 
1 [thing i want] 
2 [thing i dont want] 
3 [thing i dont want] [thing i want] 
4 // [thing i want] 
5 [thing i want] // [thing i want] 
+1

'' (?! //) 'всегда истинно, поскольку следующий потребляемый символ является' ['. Кажется, вы избегаете замены в одной строке комментариев, правильно? Сопоставьте эти комментарии и замените совпадения только в других контекстах. –

+1

Я не вижу отношения между вещами, которые вы хотите, и не делайте этого. Не могли бы вы разместить отдельный текстовый блок строки 'content', если он будет опубликован? – sln

+0

@sln. Я добавил его к исходному вопросу. – MDKF

ответ

1

Там нет реального простого способа проверить, если что-то в инлайн комментарии или нет. Механизм Java regex способен смотреть назад, но с ограниченным «расстоянием» (другими словами, он допускает ограниченные переменные длины), и я не уверен, что создание шаблона с этой функцией очень эффективно.

Что вы можете сделать, это проверить все с самого начала каждой строки с:

(?m)((?:\G|^)[^\[/\n]*+(?:\[(?!thing i want\])[^\[/\n]*|/(?!/)[^\[/\n]*)*+)\[thing i want\] 

(побег каждый символ обратной косой черты, чтобы написать строку шаблона в Java)

С заменой:

$1best thing ever 

пояснение: Цель состоит в том, чтобы захватить все с начала линии до цели или с предыдущей суммы t в одной строке до следующей. Таким образом, вы можете точно описать, что разрешено или нет до появления цели (все, что не является целью или двумя последовательными слэшами).

(?m) # switch the multi-line mode on: the^means "start of the line" 
( # open the capture group $1 
    (?: # non-capturing group: two possible starts 
     \G # contiguous to a previous match (on the same line) 
     | # OR 
     ^# at the start of the line 
    ) 

    [^\[/\n]*+ # all that is not: an opening bracket, a slash or a newline 
       # * stands for "0 or more times" and the + after forbids 
       # to backtrack in this part if the pattern fails later 
       # "*+" is called a "possessive quantifier" 
    (?: 
     \[     # literal [ 
     (?!thing i want\]) # not followed by "thing i want]" 
     [^\[/\n]*    
     |      # OR 
     /     # literal/
     (?!/)    # not followed by an other/
     [^\[/\n]* 
    )*+ # zero or more times 
) # close the capture group $1 
\[thing i want\] # the target 
+0

есть 2 пропавших] в приведенном выше? – MDKF

+0

@MDKF: нет, но '[' должен быть экранирован внутри классов символов в Java. Моя ошибка, теперь она исправлена. –

+0

@MDKF: demo (нажмите кнопку Java): http://fiddle.re/nzmv7a –