Регулярное выражение для разделения вложенных координатных строк - PullRequest
10 голосов
/ 02 февраля 2010

У меня есть строка в формате "[(1, 2), (2, 3), (3, 4)]" с произвольным количеством элементов. Я пытаюсь разбить его на запятые, разделяющие координаты, то есть получить (1, 2), (2, 3) и (3, 4).

Могу ли я сделать это в Java regex? Я полный noob, но надеюсь, что регулярное выражение Java достаточно мощный для этого. Если нет, не могли бы вы предложить альтернативу?

Ответы [ 6 ]

9 голосов
/ 02 февраля 2010

с Java 5

Scanner sc = new Scanner();
sc.useDelimiter("\\D+"); // skip everything that is not a digit
List<Coord> result = new ArrayList<Coord>();
while (sc.hasNextInt()) {
    result.add(new Coord(sc.nextInt(), sc.nextInt()));
}
return result;

РЕДАКТИРОВАТЬ: Мы не знаем, сколько координат передается в строке coords.

7 голосов
/ 02 февраля 2010

Для этого вы можете использовать String#split().

String string = "[(1, 2), (2, 3), (3, 4)]";
string = string.substring(1, string.length() - 1); // Get rid of braces.
String[] parts = string.split("(?<=\\))(,\\s*)(?=\\()");
for (String part : parts) {
    part = part.substring(1, part.length() - 1); // Get rid of parentheses.
    String[] coords = part.split(",\\s*");
    int x = Integer.parseInt(coords[0]);
    int y = Integer.parseInt(coords[1]);
    System.out.printf("x=%d, y=%d\n", x, y);
}

(?<=\\)) положительный взгляд за означает, что ему должно предшествовать ). (?=\\() положительный прогноз означает, что он должен быть заменен (. (,\\s*) означает, что он должен быть разбит на , и любой пробел после этого. \\ здесь только для того, чтобы избежать специфичных для регулярных выражений символов.

Тем не менее, конкретная строка распознается как результат List#toString(). Вы уверены, что делаете все правильно? ;)

Обновление в соответствии с комментариями, вы действительно можете сделать наоборот и избавиться от не цифр:

String string = "[(1, 2), (2, 3), (3, 4)]";
String[] parts = string.split("\\D.");
for (int i = 1; i < parts.length; i += 3) {
    int x = Integer.parseInt(parts[i]);
    int y = Integer.parseInt(parts[i + 1]);
    System.out.printf("x=%d, y=%d\n", x, y);
}

Здесь \\D означает, что он должен быть разбит на любой не -разряд (\\d обозначает цифру). . после означает, что он должен исключить любые пустые совпадения после цифр. Однако я должен признать, что я не уверен, как устранить пустые совпадения до цифр. Я еще не обученный гуру регулярных выражений. Эй, Барт К, ты можешь сделать это лучше?

В конце концов, для этого лучше использовать парсер . См. Ответ Губертса на эту тему .

3 голосов
/ 02 февраля 2010

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

\(\d+,\s\d+\)

Это выражение вернет несколько совпадений (три с вводом из вашего примера).

В своем вопросе вы утверждаете, что хотите «получить (1, 2), (2, 3) и (3, 4)». Если вам действительно нужна пара значений, связанных с каждой координатой, вы можете удалить скобки и измените регулярное выражение, чтобы сделать некоторые захваты:

(\d+),\s(\d+)

Код Java будет выглядеть примерно так:

import java.util.regex.*;

public class Test {
    public static void main(String[] args) {
        Pattern pattern = Pattern.compile("(\\d+),\\s(\\d+)");
        Matcher matcher = pattern.matcher("[(1, 2), (2, 3), (3, 4)]");

        while (matcher.find()) {
            int x = Integer.parseInt(matcher.group(1));
            int y = Integer.parseInt(matcher.group(2));
            System.out.printf("x=%d, y=%d\n", x, y);
        }
    }
}
1 голос
/ 02 февраля 2010

Если вы используете регулярное выражение, вы получите паршивые сообщения об ошибках, и все будет значительно сложнее, если ваши требования изменятся (например, если вам придется разбирать наборы в разных квадратных скобках в разные группы).

Я рекомендую вам просто написать парсер вручную, это как 10 строк кода и не должно быть очень хрупким.Отслеживайте все, что вы делаете, открывайте скобки, закрывайте скобки, открывайте скобки и закрывайте скобки.Это похоже на оператор switch с 5 опциями (и по умолчанию), что на самом деле не так уж и плохо.

Для минимального подхода открытые парены и открытые скобки можно игнорировать, поэтому на самом деле есть только 3 случая.


Это будет минимум медведя.

// Java-like psuedocode
int valuea;
String lastValue;
tokens=new StringTokenizer(String, "[](),", true);

for(String token : tokens) {  

    // The token Before the ) is the second int of the pair, and the first should
    // already be stored
    if(token.equals(")"))
        output.addResult(valuea, lastValue.toInt());

    // The token before the comma is the first int of the pair
    else if(token.equals(",")) 
        valuea=lastValue.toInt();

    // Just store off this token and deal with it when we hit the proper delim
    else
        lastValue=token;
}

Это не лучше, чем минимальное решение на основе регулярных выражений, ЗА ИСКЛЮЧЕНИЕМ, что его НАМНОГО будет легче поддерживать и улучшать.(добавьте проверку ошибок, добавьте стек для сопоставления скобок и парных скобок и проверки для неуместных запятых и другого недопустимого синтаксиса)

В качестве примера расширяемости, если вам нужно было разместить разные наборы квадратных скобокгруппируются в разные выходные наборы, тогда добавление происходит так же просто, как:

    // When we close the square bracket, start a new output group.
    else if(token.equals("]"))
        output.startNewGroup();

И проверка на наличие паренсов так же проста, как создание стека символов и добавление каждого [или (в стек, затем, когда выполучить a] или), вытолкнуть стек и утверждать, что он соответствует.Кроме того, когда вы закончите, убедитесь, что ваш стек.size () == 0.

1 голос
/ 02 февраля 2010

Всегда ли будут 3 группы координат, которые необходимо проанализировать?

Вы можете попробовать:

\[(\(\d,\d\)), (\(\d,\d\)), (\(\d,\d\))\]

0 голосов
/ 02 февраля 2010

В регулярных выражениях вы можете разделить на (?<=\)),, которые используют Положительное Взгляд назад :

string[] subs = str.replaceAll("\[","").replaceAll("\]","").split("(?<=\)),");

В строковых функциях simpe вы можете сбросить [ и ], использовать string.split("),") и вернуть ) после него.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...