Содержит ли строка три числа, разделенных запятыми? - PullRequest
1 голос
/ 11 января 2012

Как проверить, соответствует ли строка этому формату:

<number>,<number>,<number>

например.

3.0, 87546,0.8273456

т.е. три значения через запятую, которые могут быть проанализированы как двойные. Иногда строка будет содержать что-то еще (например, Text,More text,42 или anything, really), и в таком случае мне просто нужно проигнорировать это и перейти к анализу следующей строки.

Сейчас я просто пытаюсь проанализировать строку, как будто она соответствует ожидаемому формату, и перехватить любое результирующее исключение. Что умнее и дешевле это сделать? Надеюсь, не выбрасывая / ловить исключения?

        String[] parsedLine = line.trim().split(",");
        if (parsedLine.length == 3) {
            try {
                xCoordinate = Double.parseDouble(parsedLine[0]);
                yCoordinate = Double.parseDouble(parsedLine[1]);
                groundElevation = Double.parseDouble(parsedLine[2]);
            } catch (NumberFormatException nfe) {
                //This line does not contain numbers exclusively. 
                //Assume it's a header/comment.
                //Do nothing.
            }
        } else {
            //This is not in the expected x,y,z format. 
            //Assume it's a header/comment.
            //Do nothing.
        }

Ответы [ 9 ]

2 голосов
/ 11 января 2012

Я думаю, это не так дорого. String.split() создаст Pattern из вашего параметра и разделит строку вокруг него.

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

final Pattern pattern = Pattern.compile("^(\\d+(\\.\\d+)?),(\\d+(\\.\\d+)?),(\\d+(\\.\\d+)?)$");
final Matcher matcher = pattern.matcher(line);
if (matcher.matches()) {
   xCoordinate = Double.parseDouble(matcher.group(1));
   // ...
}
2 голосов
/ 11 января 2012

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

В ответ на ваши комментарии «не следует использовать исключение только в исключительных условиях», я бы сказал, что эта проблема является исключительным условием; Проблема, при которой использование исключений таким образом создает более элегантное решение.

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

2 голосов
/ 11 января 2012

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

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

2 голосов
/ 11 января 2012

Нет более чистого пути. Ваш код в порядке.

Вы спрашиваете: «Но не должны ли исключения« использоваться только в исключительных условиях »? Здесь я использую их как само собой разумеющееся».

Ну, у Java нет метода Double.isValid(String). Если бы это было, Вы могли бы использовать это, но это не так. И даже в этом случае вам придется анализировать двойное дважды: один раз, чтобы проверить, является ли оно двойным, и один раз, чтобы получить двойное значение.

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

2 голосов
/ 11 января 2012
1 голос
/ 11 января 2012

Хорошим началом было бы использование класса Pattern: boolean b = Pattern.matches(".*,.*,.*", str); Однако, чтобы убедиться, что у вас есть числа, у вас должно быть более сложное регулярное выражение:

    String str = "3.0,87546,0.8273456";
    boolean b = Pattern.matches("^(\\d+(\\.\\d+)?),(\\d+(\\.\\d+)?),(\\d+(\\.\\d+)?)$", str);
    if (b) {
        System.out.println("matches");
    } else {
        System.out.println("does not match");
    }

    // output: matches

РЕДАКТИРОВАТЬ: Я вижу, что KARASZI уже избил меня в скорости, но все же, код здесь ...

1 голос
/ 11 января 2012

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

public boolean matches(String str) {
    final String Digits     = "(\\p{Digit}+)";
    final String HexDigits  = "(\\p{XDigit}+)";
    final String Exp        = "[eE][+-]?"+Digits;
    final String fpRegex    =
            ("[\\x00-\\x20]*"+  // Optional leading "whitespace"
                    "[+-]?(" + // Optional sign character
                    "NaN|" +           // "NaN" string
                    "Infinity|" +      // "Infinity" string

                    // A decimal floating-point string representing a finite positive
                    // number without a leading sign has at most five basic pieces:
                    // Digits . Digits ExponentPart FloatTypeSuffix
                    //
                    // Since this method allows integer-only strings as input
                    // in addition to strings of floating-point literals, the
                    // two sub-patterns below are simplifications of the grammar
                    // productions from the Java Language Specification, 2nd
                    // edition, section 3.10.2.

                    // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
                    "((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+

                    // . Digits ExponentPart_opt FloatTypeSuffix_opt
                    "(\\.("+Digits+")("+Exp+")?)|"+

                    // Hexadecimal strings
                    "((" +
                    // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
                    "(0[xX]" + HexDigits + "(\\.)?)|" +

                    // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
                    "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +

                    ")[pP][+-]?" + Digits + "))" +
                    "[fFdD]?))" +
                    "[\\x00-\\x20]*");// Optional trailing "whitespace"

    String pattern=fpRegex + "," + fpRegex + "," + fpRegex;
    return str.matches(pattern);
}
0 голосов
/ 11 января 2012

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

[0-9]+(\.[0-9]*)?,[0-9]+(\.[0-9]*)?,[0-9]+(\.[0-9]*)?

Я только что внес изменения

[0-9]+(\.[0-9]*)?\s*,\s*[0-9]+(\.[0-9]*)?\s*,\s*[0-9]+(\.[0-9]*)?

Это будет дружественно к месту. Конечно, вам придется проверить это, хотя

0 голосов
/ 11 января 2012

Вы можете использовать regex \ d для цифр.так что-то вроде этого

\ d +, \ d +, \ d +

извините, не проверено:)

...