Как считать значения из чисел, записанных как слова?

Что такое NullPointerException?

Хорошим местом для начала является JavaDocs . Они охватывают это:

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

  • Вызов метода экземпляра нулевого объекта.
  • Доступ или изменение поля нулевого объекта.
  • Выполнение длины null, как если бы это был массив.
  • Доступ или изменение слотов с нулевым значением, как если бы это был массив.
  • Бросать нуль, как если бы это было значение Throwable.

Приложения должны бросать экземпляры этого класса для указания других незаконных видов использования нулевого объекта.

blockquote>

Также, если вы попытаетесь использовать нулевую ссылку с synchronized, который также выдаст это исключение, за JLS :

SynchronizedStatement:
    synchronized ( Expression ) Block
  • В противном случае, если значение выражения равно null, NullPointerException.
blockquote>

Как это исправить?

Итак, у вас есть NullPointerException. Как вы это исправите? Возьмем простой пример, который выдает NullPointerException:

public class Printer {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}

Идентифицирует нулевые значения

. Первый шаг - точно определить , значения которого вызывают исключение . Для этого нам нужно выполнить некоторую отладку. Важно научиться читать stacktrace . Это покажет вам, где было выбрано исключение:

Exception in thread "main" java.lang.NullPointerException
    at Printer.printString(Printer.java:13)
    at Printer.print(Printer.java:9)
    at Printer.main(Printer.java:19)

Здесь мы видим, что исключение выбрано в строке 13 (в методе printString). Посмотрите на строку и проверьте, какие значения равны нулю, добавив протоколирующие операторы или используя отладчик . Мы обнаруживаем, что s имеет значение null, а вызов метода length на него вызывает исключение. Мы видим, что программа перестает бросать исключение, когда s.length() удаляется из метода.

Трассировка, где эти значения взяты из

Затем проверьте, откуда это значение. Следуя вызовам метода, мы видим, что s передается с printString(name) в методе print(), а this.name - null.

Трассировка, где эти значения должны быть установлены

Где установлен this.name? В методе setName(String). С некоторой дополнительной отладкой мы видим, что этот метод вообще не вызывается. Если этот метод был вызван, обязательно проверьте порядок , что эти методы вызывают, а метод set не будет называться после методом печати. ​​

Этого достаточно, чтобы дать нам решение: добавить вызов printer.setName() перед вызовом printer.print().

Другие исправления

Переменная может иметь значение по умолчанию setName может помешать ему установить значение null):

private String name = "";

Либо метод print, либо printString может проверить значение null например:

printString((name == null) ? "" : name);

Или вы можете создать класс, чтобы name всегда имел ненулевое значение :

public class Printer {
    private final String name;

    public Printer(String name) {
        this.name = Objects.requireNonNull(name);
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer("123");
        printer.print();
    }
}

См. также:

Я все еще не могу найти проблему

Если вы попытались отладить проблему и до сих пор не имеете решения, вы можете отправить вопрос для получения дополнительной справки, но не забудьте включить то, что вы пробовали до сих пор. Как минимум, включите stacktrace в вопрос и отметьте важные номера строк в коде. Также попробуйте сначала упростить код (см. SSCCE ).

50
задан 11 revs, 5 users 95% 20 May 2018 в 20:03
поделиться

9 ответов

Я играл вокруг с синтаксическим анализатором ШТЕПСЕЛЯ, чтобы сделать то, что Вы хотели (и может отправить это как отдельный ответ позже), когда я заметил, что существует очень простой алгоритм, который делает удивительно хорошее задание со стандартными формами чисел на английском, испанском и немецком языке, по крайней мере.

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

"one" -> 1, "two" -> 2, ... "twenty" -> 20,
"dozen" -> 12, "score" -> 20, ...
"hundred" -> 100, "thousand" -> 1000, "million" -> 1000000

... и т.д

алгоритм справедлив:

total = 0
prior = null
for each word w
    v <- value(w) or next if no value defined
    prior <- case
        when prior is null:       v
        when prior > v:     prior+v
        else                prior*v
        else
    if w in {thousand,million,billion,trillion...}
        total <- total + prior
        prior <- null
total = total + prior unless prior is null

, Например, это прогрессирует следующим образом:

total    prior      v     unconsumed string
    0      _              four score and seven 
                    4     score and seven 
    0      4              
                   20     and seven 
    0     80      
                    _     seven 
    0     80      
                    7 
    0     87      
   87

total    prior      v     unconsumed string
    0        _            two million four hundred twelve thousand eight hundred seven
                    2     million four hundred twelve thousand eight hundred seven
    0        2
                  1000000 four hundred twelve thousand eight hundred seven
2000000      _
                    4     hundred twelve thousand eight hundred seven
2000000      4
                    100   twelve thousand eight hundred seven
2000000    400
                    12    thousand eight hundred seven
2000000    412
                    1000  eight hundred seven
2000000  412000
                    1000  eight hundred seven
2412000     _
                      8   hundred seven
2412000     8
                     100  seven
2412000   800
                     7
2412000   807
2412807

И так далее. Я не говорю, что это идеально подходит, но для быстрого и грязного, это вполне успевает.

<час>

Обращение к Вашему определенному списку на редактировании:

  1. кардинал/номинал или ординал: "один" и "сначала" - просто помещает их в словарь
  2. английский язык/британцы: "сорок" / "сорок" - так же
  3. сотни/тысячи: 2100-> "две тысячи сто" и также "две тысячи сто" - работы, как
  4. разделители: "одна тысяча сто пятьдесят два", но также и "elevenhundred fiftytwo" или "одна тысяча сто пятьдесят два" и этажерка - просто определяют "следующее слово", чтобы быть самым длинным префиксом, который распознает определенное слово, или до следующего неслова, если ни один не делает для запуска
  5. colloqialisms: "человек тридцати с чем-то лет" - работы
  6. фрагменты: 'одна треть', 'две пятых' - мм, еще...
  7. общие названия: 'дюжина', 'половина' - работы; можно даже сделать вещи как "полдюжина"

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

46
ответ дан MarkusQ 7 November 2019 в 10:56
поделиться

Попробуйте

  1. , Открывают Запрос HTTP для" http://www.google.com/search?q= " + число + "+in+decimal".

  2. Синтаксический анализ результат для Вашего числа.

  3. Кэшируют число / пары результата к уроку запросы со временем.

-1
ответ дан DrFloyd5 7 November 2019 в 10:56
поделиться

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

-2
ответ дан ʞɔıu 7 November 2019 в 10:56
поделиться

Моя реализация LPC некоторых Ваших требований (только американский вариант английского языка):

internal mapping inordinal = ([]);
internal mapping number = ([]);

#define Numbers ([\
    "zero"        : 0, \
    "one"         : 1, \
    "two"         : 2, \
    "three"       : 3, \
    "four"        : 4, \
    "five"        : 5, \
    "six"         : 6, \
    "seven"       : 7, \
    "eight"       : 8, \
    "nine"        : 9, \
    "ten"         : 10, \
    "eleven"      : 11, \
    "twelve"      : 12, \
    "thirteen"    : 13, \
    "fourteen"    : 14, \
    "fifteen"     : 15, \
    "sixteen"     : 16, \
    "seventeen"   : 17, \
    "eighteen"    : 18, \
    "nineteen"    : 19, \
    "twenty"      : 20, \
    "thirty"      : 30, \
    "forty"       : 40, \
    "fifty"       : 50, \
    "sixty"       : 60, \
    "seventy"     : 70, \
    "eighty"      : 80, \
    "ninety"      : 90, \
    "hundred"     : 100, \
    "thousand"    : 1000, \
    "million"     : 1000000, \
    "billion"     : 1000000000, \
])

#define Ordinals ([\
    "zeroth"        : 0, \
    "first"         : 1, \
    "second"        : 2, \
    "third"         : 3, \
    "fourth"        : 4, \
    "fifth"         : 5, \
    "sixth"         : 6, \
    "seventh"       : 7, \
    "eighth"        : 8, \
    "ninth"         : 9, \
    "tenth"         : 10, \
    "eleventh"      : 11, \
    "twelfth"       : 12, \
    "thirteenth"    : 13, \
    "fourteenth"    : 14, \
    "fifteenth"     : 15, \
    "sixteenth"     : 16, \
    "seventeenth"   : 17, \
    "eighteenth"    : 18, \
    "nineteenth"    : 19, \
    "twentieth"     : 20, \
    "thirtieth"     : 30, \
    "fortieth"      : 40, \
    "fiftieth"      : 50, \
    "sixtieth"      : 60, \
    "seventieth"    : 70, \
    "eightieth"     : 80, \
    "ninetieth"     : 90, \
    "hundredth"     : 100, \
    "thousandth"    : 1000, \
    "millionth"     : 1000000, \
    "billionth"     : 1000000000, \
])

varargs int denumerical(string num, status ordinal) {
    if(ordinal) {
        if(member(inordinal, num))
            return inordinal[num];
    } else {
        if(member(number, num))
            return number[num];
    }
    int sign = 1;
    int total = 0;
    int sub = 0;
    int value;
    string array parts = regexplode(num, " |-");
    if(sizeof(parts) >= 2 && parts[0] == "" && parts[1] == "-")
        sign = -1;
    for(int ix = 0, int iix = sizeof(parts); ix < iix; ix++) {
        string part = parts[ix];
        switch(part) {
        case "negative" :
        case "minus"    :
            sign = -1;
            continue;
        case ""         :
            continue;
        }
        if(ordinal && ix == iix - 1) {
            if(part[0] >= '0' && part[0] <= '9' && ends_with(part, "th"))
                value = to_int(part[..<3]);
            else if(member(Ordinals, part))
                value = Ordinals[part];
            else
                continue;
        } else {
            if(part[0] >= '0' && part[0] <= '9')
                value = to_int(part);
            else if(member(Numbers, part))
                value = Numbers[part];
            else
                continue;
        }
        if(value < 0) {
            sign = -1;
            value = - value;
        }
        if(value < 10) {
            if(sub >= 1000) {
                total += sub;
                sub = value;
            } else {
                sub += value;
            }
        } else if(value < 100) {
            if(sub < 10) {
                sub = 100 * sub + value;
            } else if(sub >= 1000) {
                total += sub;
                sub = value;
            } else {
                sub *= value;
            }
        } else if(value < sub) {
            total += sub;
            sub = value;
        } else if(sub == 0) {
            sub = value;
        } else {
            sub *= value;
        }
    }
    total += sub;
    return sign * total;
}
2
ответ дан fmsf 7 November 2019 в 10:56
поделиться

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

(?<Value>(?:zero)|(?:one|first)|(?:two|second)|(?:three|third)|(?:four|fourth)|
(?:five|fifth)|(?:six|sixth)|(?:seven|seventh)|(?:eight|eighth)|(?:nine|ninth)|
(?:ten|tenth)|(?:eleven|eleventh)|(?:twelve|twelfth)|(?:thirteen|thirteenth)|
(?:fourteen|fourteenth)|(?:fifteen|fifteenth)|(?:sixteen|sixteenth)|
(?:seventeen|seventeenth)|(?:eighteen|eighteenth)|(?:nineteen|nineteenth)|
(?:twenty|twentieth)|(?:thirty|thirtieth)|(?:forty|fortieth)|(?:fifty|fiftieth)|
(?:sixty|sixtieth)|(?:seventy|seventieth)|(?:eighty|eightieth)|(?:ninety|ninetieth)|
(?<Magnitude>(?:hundred|hundredth)|(?:thousand|thousandth)|(?:million|millionth)|
(?:billion|billionth)))

Показанный здесь с разрывами строки для форматирования целей..

Так или иначе, мой метод должен был выполнить этот RegEx с библиотекой как PCRE и затем считать назад именованные соответствия. И это работало надо всеми различными примерами, перечисленными в этом вопросе, минус "Одна Половина", типы, поскольку я не включал их, но как Вы видите, не было бы трудно сделать так. Это решает много проблем. Например, это обращается к следующим объектам в исходном вопросе и других ответах:

  1. кардинал/номинал или ординал: "один" и "сначала"
  2. общие орфографические ошибки: "сорок" / "сорок" (Отмечают, что это ЯВНО не обращается к этому, которое было бы чем-то, которое Вы захотите сделать перед передачей строки этому синтаксическому анализатору. Этот синтаксический анализатор рассматривает этот пример как "ЧЕТЫРЕ"...)
  3. сотни/тысячи: 2100-> "две тысячи сто" и также "две тысячи сто"
  4. разделители: "одна тысяча сто пятьдесят два", но также и "elevenhundred fiftytwo" или "одна тысяча сто пятьдесят два" и этажерка
  5. colloqialisms: "человек тридцати с чем-то лет" (Это также не ПОЛНОСТЬЮ обращено, как, что такое "что-то"? Ну, этот код находит это число как просто "30"). **

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

char *ones[] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve",
  "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"};
char *tens[] = {"", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"};
char *ordinalones[] = { "", "first", "second", "third", "fourth", "fifth", "", "", "", "", "", "", "twelfth" };
char *ordinaltens[] = { "", "", "twentieth", "thirtieth", "fortieth", "fiftieth", "sixtieth", "seventieth", "eightieth", "ninetieth" };
and so on...

легкая часть здесь, мы только храним слова тот вопрос. В случае ШЕСТОГО Вы заметите, что нет записи для него, потому что это просто, это - нормальное число с TH, прикрепляемым на... Но как ДВЕНАДЦАТЬ потребностей другое внимание.

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

Одна вещь, которую я рекомендовал бы, состоит в том, чтобы отфильтровать или съесть слово "И". Это не необходимо, и только приводит к другим проблемам.

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

Все соответствия ЗНАЧЕНИЯ ДОБАВЛЯЮТСЯ к Вашему результату, в то время как соответствия magnitutde умножают результат на значение mag. Так, Двести пятьдесят тысяч становится "2", тогда "2 * 100", тогда "200 + 50", тогда "250 * 1000", заканчиваясь с 250 000...

Только для забавы, я записал vbScript версию этого, и она работала отлично со всеми обеспеченными примерами. Теперь, это не поддерживает названные соответствия, таким образом, я должен был работать немного более трудное получение корректного результата, но я получил его. Нижняя строка, если это - соответствие "ЗНАЧЕНИЯ", добавьте его Ваш аккумулятор. Если это - соответствие величины, умножьте свой аккумулятор на 100, 1000, 1000000, 1000000000, и т.д... Это предоставит Вам некоторые довольно удивительные результаты и все, что необходимо сделать для корректировки для вещей как "одна половина", добавляют их к RegEx, вставляют маркер кода для них и обрабатывают их.

ну, я надеюсь, что это сообщение помогает КОМУ-ТО там. Если кто-либо хочет, я могу отправить vbScript псевдо кодом, что я раньше тестировал это с, однако, это не симпатичный код и НЕ производственный код.

, Если я могу.. Каков заключительный язык, в котором это будет записано? C++ или что-то как язык в виде сценария? Источник Greg Hewgill будет иметь большое значение в помощи, понимают, как все это объединяется.

Сообщенный мне, если я могу иметь какую-либо другую справку. Извините, я только знаю английский язык/Американца, таким образом, я не могу помочь Вам с другими языками.

2
ответ дан LarryF 7 November 2019 в 10:56
поделиться

Необходимо иметь в виду, что Европа и Америка рассчитывают по-другому.

европейский стандарт:

One Thousand
One Million
One Thousand Millions (British also use Milliard)
One Billion
One Thousand Billions
One Trillion
One Thousand Trillions

Здесь маленькая ссылка на нем.

<час>

А простой способ видеть различие следующий:

(American counting Trillion) == (European counting Billion)
5
ответ дан 5 revs, 2 users 85% 7 November 2019 в 10:56
поделиться

У меня есть некоторый код, который я записал только что: text2num. Это делает часть из того, что Вы хотите, кроме него не обрабатывает порядковые числа. Я на самом деле не использовал этот код ни для чего, таким образом, он в основном не тестируется!

11
ответ дан Greg Hewgill 7 November 2019 в 10:56
поделиться

Это не легкая проблема, и я не знаю ни о какой библиотеке, чтобы сделать это. Я мог бы сесть и попытаться записать что-то вроде этого когда-то. Я сделал бы это или в Прологе, Java или в Haskell, все же. Насколько я вижу, существует несколько проблем:

  • Токенизация: иногда, числа записаны одна тысяча сто пятьдесят два, но я видел elevenhundred fiftytwo или eleven-hundred-fifty-two и этажерку. Нужно было бы провести обзор того, какие формы на самом деле используются. Это могло бы быть особенно коварно для иврита.
  • Орфографические ошибки: это не так твердо. У Вас есть ограниченное количество слов, и немного волшебства расстояния Левенштейна должно добиться цели.
  • Альтернативные формы, как Вы уже упомянутый, существуют. Это включает порядковые / кардинальные числа, а также сорок/сорок и...
  • ... общие названия или наиболее часто используемые фразы и NES (именованные сущности). Вы хотели бы извлечь 30 из Тридцатилетней войны или 2 от Второй мировой войны?
  • Римские цифры, также?
  • Colloqialisms, такой как "человек тридцати с чем-то лет" и "Три евро и шрапнель", которую я не знал бы, как рассматривать.

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

Извините, это еще не реальный ответ, просто расширение Вашего вопроса. Я сообщу, нахожу ли я/пишу что-то.

Между прочим, если Вы интересуетесь семантикой цифр, я просто нашел интересная бумага Friederike Moltmann, обсудив некоторые вопросы относительно логической интерпретации цифр.

11
ответ дан Aleksandar Dimitrov 7 November 2019 в 10:56
поделиться

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

, например, сто первые, одиннадцатисекундные, и т.д.

Однако существует другой английский/Американский протест со словом 'и'

т.е.

сто один (английский) сто один (американец)

кроме того, использование для значения один на английском языке

тысяча = одна тысяча

... На стороне отмечают, что калькулятор Google делает удивительное задание этого.

сто три тысячи раз скорость света

И даже...

две тысячи сто плюс дюжина

... wtf?!? счет плюс дюжина в римских цифрах

4
ответ дан Fraser 7 November 2019 в 10:56
поделиться
Другие вопросы по тегам:

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