Как идентифицировать строковый образец в строке, но игнорировать, если совпадение попадает в указанный образец - PullRequest
0 голосов
/ 15 февраля 2011

Я хочу найти строку для вхождений строки, которая соответствует определенному шаблону. Затем я напишу этот уникальный список найденных строк, разделенных запятыми. Шаблон должен искать "$FOR_something", если этот шаблон не попадает в "#LOOKING( )" или "/* */", а в части _something нет других специальных символов.

Например, если у меня есть эта строка,

  "Not #LOOKING( $FOR_one $FOR_two) /* $FOR_three */ not $$$FOR_four or $FOR_four_b, but $FOR_five; and $FOR_six and not $FOR-seven or $FOR_five again"

Результирующий список найденных шаблонов, которые я ищу из приведенной выше строки, будет:

$FOR_five, $FOR_six

Я начал с этого примера:

import java.lang.StringBuffer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class testIt {
public static void main(String args[]) {

String myWords = "Not #LOOKING( $FOR_one $FOR_two) /* $FOR_three */ not $$$FOR_four or $FOR_four_b, but $FOR_five; and $FOR_six and not $FOR-seven or $FOR_five again";

StringBuffer sb = new StringBuffer(0);

if ( myWords.toUpperCase().contains("$FOR") )
{
   Pattern p = Pattern.compile("\\$FOR[\\_][a-zA-Z_0-9]+[\\s]*", Pattern.CASE_INSENSITIVE);
   Matcher m = p.matcher(myWords);

   String myFors = "";
   while (m.find())
   {
      myFors = myWords.substring( m.start() , m.end() ).trim();
      if ( sb.length() == 0 ) sb = sb.append(myFors);
      else
      {
         if ( !(sb.toString().contains(myFors))) sb = sb.append(", " + myFors );
      }
   }
}
System.out.println(sb);
}

}

Но это не дает мне то, что я хочу. То, что я хочу, это:

$FOR_five, $FOR_six 

Вместо этого я получаю все $ FOR_somethings. Я не знаю, как игнорировать события внутри /**/ или #LOOKING(). Какие-либо предложения?

1 Ответ

0 голосов
/ 15 февраля 2011

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

Что бы я порекомендовал вам сделать, это сначала использовать токенизацию / ручной разбор строк для отбрасывания нежелательных данных, таких как /* ... */ или #LOOKING( .... ). Однако это также может быть удалено другим регулярным выражением, таким как:

myWords.replaceAll("/\\*[^*/]+\\*/", "");      // removes /* ... */
myWords.replaceAll("#LOOKING\\([^)]+\\)", ""); // removes #LOOKING( ... )

После удаления контекстного контента вы можете использовать, например, следующее регулярное выражение:

(?<!\\$)\\$FOR_\\p{Alnum}+(?=[\\s;])

Объяснение:

(?<!\\$)         // Match iff not prefixed with $
\\$FOR_          // Matches $FOR_
\\p{Alnum}+      // Matches one or more alphanumericals [a-zA-Z0-9]
(?=[\\s;])       // Match iff followed by space or ';'

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

...