(Java) Как проанализировать строку координат с несколькими возможными форматами и преобразовать их в целые числа? - PullRequest
0 голосов
/ 10 сентября 2018

У меня есть метод, который принимает (X, Y) координатные строки от пользователя. Координаты X и Y находятся в диапазоне от 0 до 8, и координаты могут быть одного из пяти возможных форматов:

  • (4,3) : координаты X и Y указаны в скобках и разделены запятой и без пробела
  • 4 3 : координаты X и Y разделены только пробелом, без скобок
  • 4,3 : координаты X и Y разделены только запятой, без скобок
  • d 3 : X представлен буквами. 0 = A, 1 = B, ..., 8 = H. X и Y разделены пробелом
  • d3 : То же, что и выше, без пробелов.

У меня возникли проблемы с разработкой единого метода, который может успешно анализировать все четыре формата. Точнее говоря, я хочу успешно преобразовать координаты X и Y в две отдельные целые и хранить их где-то независимо от используемого формата.

Я немного новичок в Java, и у меня нет большого опыта разбора строк. Любые указатели будут оценены.

Ответы [ 3 ]

0 голосов
/ 10 сентября 2018

Вы можете сделать это как шаги:

  • удалить все символы, которые не являются цифрами или буквами, вы закончите с двумя символами
  • посмотрите каждый из двух:
    • если цифра: проанализировать int
    • , если не удалить код символа 'a' и добавить +1, чтобы получить a = 1, b = 2, ...
private static int[] parseToCoord(String s) {
    String[] xy = s.replaceAll("[^\\w\\d]", "").toLowerCase().split("");
    int[] res = new int[2];
    res[0] = xy[0].matches("\\d") ? Integer.parseInt(xy[0]) : xy[0].charAt(0) - 'a' + 1;
    res[1] = xy[1].matches("\\d") ? Integer.parseInt(xy[1]) : xy[1].charAt(0) - 'a' + 1;
    return res;
}

Stream версия

private static int[] parseToCoordStream(String s) {
    return Stream.of(s.replaceAll("[^\\w\\d]", "").toLowerCase().split(""))
            .mapToInt(val -> val.matches("\\d") ? Integer.parseInt(val) : val.charAt(0) - 'a' + 1)
            .toArray();
}

Использование

public static void main(String args[]) throws Exception {
    for (String s : Arrays.asList("(4,3)", "4 3", "4,3", "d 3", "d3", "D3")) {
        int[] xy = parseToCoord(s);
        System.out.println(xy[0] + " " + xy[1]);
    }
}
0 голосов
/ 10 сентября 2018

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

Программа запускается из командной строки, например:

> java CoordinateParser "d 7"


Код примера :

import java.util.*;

public class CoordinateParser {

    private static final Map<Character, Integer> charIntMap = new HashMap<>();
    static {
        charIntMap.put('a', 0);
        charIntMap.put('b', 1);
        charIntMap.put('c', 2);
        charIntMap.put('d', 3);
        charIntMap.put('e', 4);
        charIntMap.put('f', 5);
        charIntMap.put('g', 6);
        charIntMap.put('h', 7);
        charIntMap.put('i', 8);
    }

    public static void main (String [] args) {

        if (args.length != 1) {
            System.out.println("Program needs input string argument, for example:");
            System.out.println("java CoordinateParser \"d7\"");
            System.out.println("Exiting the program.");
            System.exit(0);
        }

        System.out.println("Input: " + args[0]);

        XYCoordinates xy = new CoordinateParser().getCoordinates(args[0]);
        System.out.println("Co-ordinates: " + xy);
    }

    private XYCoordinates getCoordinates(String input)
            throws NumberFormatException {

        input = input.trim();

        if (input.length() < 2 || input.length() > 5) {
            throw new IllegalArgumentException("Invalid input string length: " + input);
        }

        if (input.length() == 5 && input.startsWith("(") && input.endsWith(")")) {
            return new XYCoordinates(input.substring(1, 2), input.substring(3, 4));
        }

        if (input.length() == 3 && input.contains(",")) {
            return new XYCoordinates(input.substring(0, 1), input.substring(2, 3));
        }       

        if (input.length() == 3 && input.contains(" ")) {
            String x = input.substring(0, 1);
            Integer i = charIntMap.get(x.charAt(0));
            if (i != null) {
                return new XYCoordinates(Integer.toString(i), input.substring(2, 3));
            }
        }           

        if (input.length() == 2) {
            String x = input.substring(0, 1);
            Integer i = charIntMap.get(x.charAt(0));
            if (i != null) {
                return new XYCoordinates(Integer.toString(i), input.substring(1, 2));
            }
        }

        throw new IllegalArgumentException("Invalid input format: " + input);
    }

    /*
     * Inner class represents x and y co-ordinates.
     */
    private class XYCoordinates {

        private int x;
        private int y;

        XYCoordinates(String xStr, String yStr) 
                throws NumberFormatException {

            try {
                x = Integer.parseInt(xStr);
                y = Integer.parseInt(yStr);
            }
            catch (NumberFormatException ex) {
                throw new NumberFormatException("Invalid co-ordinates: " +
                    new StringJoiner(", ", "(", ")")
                        .add(xStr).add(yStr).toString());
            }

            if (isNotValidValue(x) || isNotValidValue(y)) {
                throw new IllegalArgumentException("Co-ordinates out of range: " + toString());
            }
        }

        private boolean isNotValidValue(int i) {
            return (i < 0 || i > 8);
        }

        int getX() {
            return x;
        }

        int getY() {
            return y;
        }

        @Override
        public String toString() {
            return new StringJoiner(", ", "(", ")")
                .add(Integer.toString(x))
                .add(Integer.toString(y))
                .toString();
        }
    }
}


XYКоординатный класс :

POJO (Простой старый Java-объект) представляет объект, в данном случае определенный классом XYCoordinates (имеет набор координат x и y). Преимущества наличия POJO:

  • Можно легко получить индивидуальные координаты; например, getX() и getY().
  • Получить строковое представление координат - переопределив toString метод, унаследованный от java.lang.Object.
  • Сравните две координаты одинаковые (или равные), переопределив Object метод класса equals (два набора координат с одинаковым x и значения y можно считать равными).
  • Хранить некоторые координаты в коллекции и эффективно их извлекать (может помочь переопределение метода Object класса *1037*).

Вот некоторые из преимуществ. Кроме того, другие атрибуты или поведение могут быть определены для класса POJO по мере необходимости; приходит на ум сравнение двух координат и сортировка набора координат (вспомните функциональные интерфейсы Comparable и Comparator).

0 голосов
/ 10 сентября 2018

Сначала давайте рассмотрим основной формат. Формат, в который мы хотим преобразовать все это, чтобы окончательно преобразовать их в два целых числа. Давайте сделаем этот формат двумя числами, разделенными пробелом. Это IMO проще всего разобрать.

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

Это три вниз, 2 вперед.

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

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

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

Вот так я бы сделал это в коде.

  public int[] parseXYCoord(String s) {
    String master=s;
    if(s.contains(",")){
        master=master.replace("(","").replace(")","");
        master=master.replace(","," ");
    }else if(master.matches("^[a-z]((\\s[0-8])|[0-8])$")){
        int charValue=master.charAt(0)-'a'+1;
        master=charValue+" "+master.charAt(master.contains(" ")?2:1);


    }
    return parseMaster(master);
}

private int[] parseMaster(String master) {
    if(!master.matches("^[0-8] [0-8]$"))
        throw new IllegalArgumentException("Inputted Number is incorrect!");
    String[] splitMaster=master.split(" ");
    return new int[]{Integer.parseInt(splitMaster[0]),Integer.parseInt(splitMaster[1])};

}

Я не слишком хорош в регулярных выражениях. Хотя это и некрасиво, но работа сделана. Посетите сайт DebugRegex , если вы хотите узнать, как использовать регулярные выражения.

Тестирование с использованием

    System.out.println(Arrays.toString(parseXYCoord("4,3")));
    System.out.println(Arrays.toString(parseXYCoord("4 3")));
    System.out.println(Arrays.toString(parseXYCoord("(4,3)")));
    System.out.println(Arrays.toString(parseXYCoord("d3")));
    System.out.println(Arrays.toString(parseXYCoord("d 3")));

печатает

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