2013-06-18 4 views
2

Метод getPolygonPoints() (смотри ниже) становится имя строки в качестве параметра, который выглядит примерно так:Regex - извлечь неограниченное количество хитов

points={{-100,100},{-120,60},{-80,60},{-100,100},{-100,100}} 

Первое число обозначает х-координаты, второй для координаты y. Например, первая точка

x=-100 
y=100 

Второй пункт

x=-120 
y=60 

и так далее.

Теперь я хочу, чтобы извлечь точки строки и поместить их в ArrayList, который должен выглядеть в конце:

[-100, 100, -120, 60, -80, 60, -100, 100, -100, 100] 

Особенность здесь в том, что количество точек данная строка изменяется и не всегда одинакова.

Я написал следующий код:

private ArrayList<Integer> getPolygonPoints(String name) { 
    // the regular expression 
    String regGroup = "[-]?[\\d]{1,3}"; 
    // compile the regular expression into a pattern 
    Pattern regex = Pattern.compile("\\{(" + regGroup + ")"); 
    // the mather 
    Matcher matcher; 

    ArrayList<Integer> points = new ArrayList<Integer>(); 

    // matcher that will match the given input against the pattern 
    matcher = regex.matcher(name); 
    int i = 1; 
    while(matcher.find()) { 
     System.out.println(Integer.parseInt(matcher.group(i))); 
     i++; 
    } 
    return points; 
} 

Первая координата х извлекается правильно, но затем IndexOutOfBoundsException брошен. Я думаю, что это происходит, потому что группа 2 не определена. Я думаю, что сначала мне приходится подсчитывать точки, а затем перебирать это число. Внутри итерации я бы поставил значения int в ArrayList с помощью простого add(). Но я не знаю, как это сделать. Может быть, я не понимаю часть регулярного выражения на этом этапе. Особенно, как работают группы.

Пожалуйста, помогите!

+1

В вашем регулярном выражении есть только 1 группа, которая является частью, заключенной в(), поэтому вы не можете получить доступ к группе 2 или 3, так как ее нет. просто замените matcher.group (i) на matcher.group (1) в вашем совпадающем цикле – Regenschein

+0

Почему бы вам не сделать SPLIT и REPLACE? – NeverHopeless

ответ

0

Как делать это только в одной строке:

List<String> list = Arrays.asList(name.replaceAll("(^\\w+=\\{+)|(\\}+$)", "").split("\\{?,\\}?")); 

весь Ваш метод будет затем:

private ArrayList<Integer> getPolygonPoints(String name) { 
    return new ArrayList<String>(Arrays.asList(name.replaceAll("(^\\w+=\\{+)|(\\}+$)", "").split("\\{?,\\}?"))); 
} 

Это работает первый отгонкой начальные и завершающие текст, а затем расщепляется на запятых опционально окруженный брекетами.

BTW Вы действительно должны вернуть абстрактный тип List, а не конкретную реализацию ArrayList.

+0

Кроме того, входная строка начинается с 'points = {', ​​а не скобки. – millimoose

+0

@millimoose Я неправильно прочитал Q. Я исправил ведущую часть «points =». И теперь я возвращаю ArrayList. Благодарю. – Bohemian

4

Часть, которую вы, кажется, не понимаете в API регулярных выражений, состоит в том, что номер группы захвата «перезагружается» при каждом звонке до find(). Или, говоря иначе: номер группы захвата - это его позиция в шаблоне , а не в строке ввода .

Вы тоже ошибаетесь. Вы должны соответствовать всей конструкции, которую вы ищете, в этом случае пары {x,y}.Я предполагаю, что вы не хотите, чтобы подтвердить формат всей строки, так что мы можем игнорировать внешние скобки и запятые:

Pattern p = Pattern.compile("\\{(-?\\d+),(-?\\d+)\\}"); 
Matcher m = p.matcher(name); 

while (m.find()) { 
    String x = m.group(1); 
    String y = m.group(2); 
    // parse and add to list 
} 

Попеременно, так как вы не заботитесь о том, какие координаты X и которая является Y, вы даже можете сделать:

Matcher m = Pattern.compile("-?\\d+").matcher(name); 
while (m.find()) { 
    String xOrY = m.group(); 
    // parse etc. 
} 

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

+0

интересное решение –

4
String points = "{{-100,100},{-120,60},{-80,60},{-100,100},{-100,100}}"; 

String[] strs = points.replaceAll("(\\{|\\})", "").split(","); 

ArrayList<Integer> list = new ArrayList<Integer>(strs.length); 

for (String s : strs) 
{ 
    list.add(Integer.valueOf(s)); 
} 
+0

+1: также хороший «либеральный» подход. – millimoose

+0

+1 Это то, что я хочу предпочесть и нуждаюсь в подтверждении от ОП, если это возможно. – NeverHopeless

0

Вы также можете попробовать это регулярное выражение:

((-?\d+)\s*,\s*(-?\d+)) 

Это даст вам три группы:

Group 1 : x 
Group 2 : y 
Group 3 : x,y 

Вы можете использовать который требуется для вас.

+0

Я бы рекомендовал использовать названные группы в этом случае. REs достаточно сложны, не задумываясь о нумерации вложенных групп захвата. – millimoose

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