Regex, чтобы найти запятые, которые не находятся внутри "(и)" - PullRequest
5 голосов
/ 07 августа 2010

Мне нужна помощь для моделирования этого регулярного выражения.Я думаю, что будет проще с примером.Мне нужно регулярное выражение, которое соответствует запятой, но только если оно не находится внутри этой структуры: "( )", например:

,a,b,c,d,"("x","y",z)",e,f,g,

Тогда первые пять и последние четыре запятые должны соответствовать выражению,два между xyz и внутри раздела ( ) не должны.

Я перепробовал много комбинаций, но регулярные выражения все еще немного туманны для меня.

Я хочу использовать егос помощью метода split в Java.Пример короткий, но он может быть намного длиннее и иметь более одного раздела между «(и)».Метод split получает выражение, и если некоторый текст (в данном случае запятая) соответствует выражению, он будет разделителем.

Итак, вы хотите сделать что-то вроде этого:

String keys[] = row.split(expr);
System.out.println(keys[0]); // print a
System.out.println(keys[1]); // print b
System.out.println(keys[2]); // print c
System.out.println(keys[3]); // print d
System.out.println(keys[4]); // print "("x","y",z)"
System.out.println(keys[5]); // print e
System.out.println(keys[6]); // print f
System.out.println(keys[7]); // print g

Спасибо!

Ответы [ 6 ]

14 голосов
/ 07 августа 2010

Вы можете сделать это с негативным взглядом. Вот несколько упрощенная задача для иллюстрации идеи:

String text = "a;b;c;d;<x;y;z>;e;f;g;<p;q;r;s>;h;i;j";

String[] parts = text.split(";(?![^<>]*>)");

System.out.println(java.util.Arrays.toString(parts));
//  _  _  _  _  _______  _  _  _  _________  _  _  _
// [a, b, c, d, <x;y;z>, e, f, g, <p;q;r;s>, h, i, j]

Обратите внимание, что вместо , в качестве разделителя теперь используется ;, а вместо "( и ") круглые скобки просто < и >, но идея по-прежнему работает.


По шаблону

[…] - это класс символов . Нечто вроде [aeiou] соответствует одному из строчных гласных. [^…] является отрицательным классом символов. [^aeiou] соответствует одному из всего, кроме строчных гласных.

Спецификатор повторения * может использоваться для соответствия «нулю или более раз» предыдущего шаблона.

(?!…) - негативный взгляд; он может использоваться для подтверждения того, что определенный шаблон НЕ совпадает, глядя вперед (т.е. вправо) текущей позиции.

Шаблон [^<>]*> соответствует последовательности (возможно, пустой) всего, кроме скобок, после чего следует парантез закрывающего типа.

Собрав все вышеперечисленное вместе, мы получим ;(?![^<>]*>), что соответствует ;, но только если мы не сможем увидеть закрывающую скобку в качестве первой скобки справа от нее, потому что свидетельство такого явления будет означать только то, что ; находится внутри скобок.

Эта техника с некоторыми изменениями может быть адаптирована к исходной задаче. Не забудьте экранировать метасимволы регулярных выражений ( и ), если необходимо, и, конечно, ", а также \ в строковом литерале Java должны быть экранированы с помощью предшествующего \.

Вы также можете использовать * для улучшения производительности, т. Е. ;(?![^<>]*+>).

Ссылки

6 голосов
/ 07 августа 2010

Попробуйте это:

(?![^(]*\)),

У меня сработало в моем тестировании, все запятые не в скобках.

Редактировать: Гопи указал на необходимость избежать косой черты в Java:

(?![^(]*\\)),

Редактировать: Алан Мур указал на некоторые ненужные сложности. Исправлено.

2 голосов
/ 07 августа 2010

Если парены правильно спарены и не могут быть вложенными, вы можете сначала разбить текст на парены, а затем обработать фрагменты.

List<String> result = new ArrayList<String>();
String[] chunks = text.split("[()]");
for (int i = 0; i < chunks.length; i++) {
  if ((i % 2) == 0) {
    String[] atoms = chunks[i].split(",");
    for (int j = 0; j < atoms.length; j++)
      result.add(atoms[j]);
  }
  else
    result.add(chunks[i]);
}
1 голос
/ 07 августа 2010

Это должно делать то, что вы хотите:

(".*")|([a-z])

Я не проверял в java, но если вы тестируете его с http://www.fileformat.info/tool/regex.htm, группы $ 1 и $ 2 содержат правильные значения, поэтому они совпадают иВы должны получить то, что вы хотите.Немного сложнее это получится, если между запятыми есть другие более сложные значения, чем az.

Если я правильно понимаю разбиение, не используйте его, просто заполните массив обратной ссылкой $ 0, $ 0 содержит значенияты ищешь.Может быть, лучше использовать функцию соответствия, а лучше работать со значениями, потому что вы получите этот действительно простой regExp.другие решения, которые я вижу до сих пор, очень хороши, без сомнения об этом, но они действительно сложны, и через 2 недели вы действительно не знаете, что именно сделал rexExp.Перевернув саму проблему, проблема часто упрощается.

1 голос
/ 07 августа 2010

Ну,

После некоторых тестов я только нашел ответ, который делает то, что мне нужно до сих пор.В этот момент все itens внутри блока "(...)" тоже внутри "", как в: "(" a "," b "," c ")", тогда регулярное выражение ((?<!\"),)|(,(?!\")) прекрасно работаетза то, что я хочу!

Но я все еще ищу тот, который может найти запятые, даже если во внутренних терминах нет "".

Спасибо за помощь, парень.

0 голосов
/ 14 июня 2012

У меня была такая же проблема.Я выбираю ответ Адама Шмидега и улучшаю его.

Мне пришлось иметь дело с этими 3 строками, например:

  1. France (Grenoble, Lyon), Germany (Berlin, Munich)
  2. Italy, Suede, Belgium, Portugal
  3. France, Italy (Torino), Spain (Bercelona, Madrid), Austria

Идея заключалась в том, чтобы:

  1. France (Grenoble, Lyon) или Germany (Berlin, Munich)
  2. Italy, Suede, Belgium, Portugal
  3. France, Italy (Torino), Spain (Bercelona, Madrid), Austria

Я решил не использовать регулярное выражение, потому что я был на 100%что я делал и что в любом случае сработает.

String[] chunks = input.split("[()]");
for (int i = 0; i < chunks.length; i++) {
    if ((i % 2) != 0) {
        chunks[i] = "("+chunks[i].replaceAll(",", ";")+")";
    }
}
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < chunks.length; i++) {
    buffer.append(chunks[i]);
}
String s = buffer.toString();
String[] output = s.split(",");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...