SHOUTY_SNAKE_CASED НОМЕРА

WE_ALL_LOVE_ SHOUTY_SNAKE_CASE _SO_I_WROTE_A_PROGRAM_FOR_IT !! 1!

Хорошо, этого достаточно. Это из этого вопроса . Шаблон довольно прост, он принимает вход String, проверяет, является ли он численным, и если это так, преобразует его в SHOUTY_SNAKE_CASE.

  

Пример: "1231" -> "ONE_TWO_THREE_ONE"

Это довольно просто, но это также первый раз, когда я использовал потоки Java 8, поэтому мне захотелось высказаться по поводу его (простого) использования.

private static final String[] words = 
        new String[]{"zero","one","two","three","four","five","six","seven","eight","nine"};

public static String convertNumbersToWords(final String input) {

    if(input == null || !input.matches("^\\d*$")){
        throw new IllegalArgumentException("input cannot be null or non-numerical.");
    }

    return input.chars()
             .mapToObj(c -> getWordFromCharCode(c).toUpperCase())
             .collect(Collectors.joining("_"));
}

private static String getWordFromCharCode(int code){
    return words[code - 48];
}
39 голосов | спросил TopinFrassi 27 52015vEurope/Moscow11bEurope/MoscowFri, 27 Nov 2015 17:47:46 +0300 2015, 17:47:46

6 ответов


20

Поскольку вам нужен enum стертый набор LOUD_WORDS, который выравнивается с числами, предпочтительно как некоторая форма числовых индексов ... enum вместо String[] кажется идеально подходящим:

enum Word {
    ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE;
}

(я думаю, вы можете найти вывод.)

изменить: Только одна заметка об использовании Word.values(), как указано в @ Комментарии Simon : каждый раз создается новый массив, и это может быть нежелательно, с точки зрения производительности.

Поскольку вы также экспериментируете с некоторыми функциями Java 8, вам может потребоваться использовать Optional , чтобы исключить if -validation:

private static final String NUMBERS_ONLY = "^\\d+$";

// Usage
Optional.ofNullable(input)
        .filter(v -> v != null && v.matches(NUMBERS_ONLY))
        .orElseThrow(IllegalArgumentException::new)
        .chars()
        // ...

Если вы предпочитаете бросать NullPointerException для значений null, вы можете придерживаться Optional.of(T).

ответил h.j.k. 27 52015vEurope/Moscow11bEurope/MoscowFri, 27 Nov 2015 20:53:10 +0300 2015, 20:53:10
37

Почему вы храните их как строчные слова только для вызова toUpperCase на них? Храните их в том виде, в котором вы собираетесь их использовать, и сохраняйте вызов функции для каждого слова. Также более понятно, что строки сохраняются одинаково они будут напечатаны.

ответил SuperBiasedMan 27 52015vEurope/Moscow11bEurope/MoscowFri, 27 Nov 2015 17:51:37 +0300 2015, 17:51:37
20

Я бы предложил заменить код низкого уровня code - 48 на Character.getNumericValue.

Еще одно соображение может состоять в том, чтобы использовать CharMatcher.DIGIT.matchesAllOf guava вместо регулярного выражения для проверки входной строки, хотя я понимаю, что использование библиотек часто является не только точкой для CR.stackexchange. Обратите внимание, что этот подход будет передавать вам цифры с числовыми значениями, превышающими 9 (например, римская цифра 50), и вам придется подумать о способе их поддержки. (Разделить на отдельные цифры?)

ответил Benjaminssp 27 52015vEurope/Moscow11bEurope/MoscowFri, 27 Nov 2015 18:30:54 +0300 2015, 18:30:54
11

Именование и разложение метода

Давайте посмотрим на эту подпись метода:

public static String convertNumbersToWords(final String input) {

Имя метода предполагает преобразование numbers ... И оно работает со входами типа «1234». Немного неестественно, что ввод представляет собой строку, в отличие от числового типа, а «1234» - это одно число, а не множественные числа.

Кроме того, метод выполняет две функции:

  • подтверждение ввода состоит только из цифр
  • преобразуйте цифры в SHOUT_CASE

Было бы лучше разложить это на два метода, например:

private static String convertValidatedDigitsToWords(final String digits) {
    return digits.chars()
            .mapToObj(ShoutySnake::getWordFromCharCode)
            .collect(Collectors.joining("_"));
}

public static String convertDigitsToWords(final String input) {
    if (input == null || !input.matches("\\d*")) {
        throw new IllegalArgumentException("input cannot be null or non-numerical.");
    }
    return convertValidatedDigitsToWords(input);
}

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

public static String convertDigitsToWords(final int number) {
    if (number < 0) {
        throw new IllegalArgumentException("input must be non-negative");
    }
    return convertValidatedDigitsToWords(Integer.toString(number));
}

Небольшой связанный отзыв: String.matches подразумевает ^ и $, не нужно включать это в шаблон.

Оптимизация для повторных вызовов

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

private static final Pattern pattern = Pattern.compile("\\d*");

public static String convertDigitsToWords(final String input) {
    if (!pattern.matcher(input).matches()) {
        throw new IllegalArgumentException("input must be non-null and non-negative.");
    }
    return convertValidatedDigitsToWords(input);
}

Магический номер 48

В этом коде 48 является магическим числом:

private static String getWordFromCharCode(int code){
    return words[code - 48];
}

Вы можете легко сделать его менее магическим, обратившись к '0':

private static String getWordFromCharCode(int code) {
    return words[code - '0'];
}
ответил janos 28 62015vEurope/Moscow11bEurope/MoscowSat, 28 Nov 2015 18:37:07 +0300 2015, 18:37:07
10

Имя convertNumbersToWords() не содержит четкого отражения того, что делает этот метод. Вы можете сделать это, используя соглашение java, например convertNumbersToShoutySnakeCaseWords(), или таким образом, чтобы оно соответствовало цели приложения, например CONVERT_NUMBERS_TO_SHOUTY_SNAKE_CASE_WORDS()

ответил Heslacher 27 52015vEurope/Moscow11bEurope/MoscowFri, 27 Nov 2015 17:56:24 +0300 2015, 17:56:24
10

Я бы предложил изменить три мысли, которые еще не были упомянуты.

  1. Ваше регулярное выражение работает, но это не то, что я называю «легким на глазах». Как насчет следующего:

    ^[0-9]*$
    

    Когда я читаю что-то вроде этого, я сразу же думаю: «Некоторое регулярное выражение с числовыми фильтрами».

  2. Также та же тема. Вы действительно хотите разрешить пустые входы? Я бы сказал, что нет. Замените * на +:

    ^[0-9]+$
    ^\\d+$
    
  3. Мне нравится статический импорт. Это не все любимые, но, на мой взгляд, это делает код более удобочитаемым. Вот почему это было бы моим окончательным решением:

    import java.util.Optional;
    import static java.util.stream.Collectors.joining;
    
    public class ShoutySnake {
    
        private enum WORDS{ZERO,ONE,TWO,THREE,FOUR,FIVE,SIX,SEVEN,EIGHT,NINE}
    
        private static final String NUMBERS_ONLY = "^[0-9]+$";
    
        private static String getNumericalCharAsSnakeShoutCaseWord(final int codePoint){
            return WORDS.values()[Character.getNumericValue(codePoint)].name();
        }
    
        public static String convertNumbersToShoutySnakeCaseWords(final String input) {
            return Optional.ofNullable(input)
                .filter(s -> s.matches(NUMBERS_ONLY))
                .orElseThrow(() -> new IllegalArgumentException("input cannot be null, empty or non-numerical."))
                .chars()
                .mapToObj(ShoutySnake::getNumericalCharAsSnakeShoutCaseWord)
                .collect(joining("_"));
        }
    }
    
ответил Julian Liebl 28 62015vEurope/Moscow11bEurope/MoscowSat, 28 Nov 2015 01:40:07 +0300 2015, 01:40:07

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132