Справочная информация: я пытаюсь постепенно разбирать выражения, такие как "cos (1.2)". Теперь к фактическому вопросу ( примечание: что фактический вопрос в основном в следующем параграфе; остальное - разговоры о решениях, которые, кажется, почти работают ):
Предположим, у меня есть строка в Java, который может начинаться с числа с плавающей запятой, а затем после него есть еще несколько «вещей». Например, у меня может быть 52hi (который начинается с «52» и заканчивается «hi») или -1.2e1e9 (который начинается с «-1.2e1», также известный как «отрицательный двенадцать» и заканчивается «e9» ). Я хочу разобрать это число в двойное число.
Заманчиво использовать Double.parseDouble, но этот метод ожидает, что строка в целом является допустимым числом, и выдает исключение, если нет. Очевидная вещь, которую нужно сделать, это написать регулярное выражение, чтобы отделить число от других вещей, а затем использовать parseDouble.
Если бы я разбирал целые числа, это было бы не так уж плохо, что-то вроде -?[0-9]+
, (Даже тогда легко забыть крайний случай, и теперь ваши пользователи не могут ввести +9 для симметрии с -9. Поэтому предыдущее регулярное выражение должно было быть [-+]?[0-9]+
.) Но для float это сложно; может быть что-то вроде этого (игнорируйте тот факт, что "." не воспринимается буквально по умолчанию в большинстве диалектов регулярных выражений):
[-+]?[0-9]*.?[0-9]*(e[-+]?[0-9]+)?
.
За исключением того, что мы только что сказали, что пустая строка является действительный номер. И так ".e2". Так что, возможно, что-то немного сложнее. Или, может быть, у меня может быть «неаккуратное» регулярное выражение, подобное приведенному выше, которое допускает некоторые не числа, если это не запрещает какие-либо действительные числа. Но в какой-то момент я начинаю думать про себя: «Разве это не должно быть работой parseDouble?». Он выполняет большую часть работы, необходимой для выяснения, где в строке заканчивается число и начинается другой материал, потому что в противном случае он не смог бы выдать исключение. Зачем мне это делать?
Поэтому я начал искать, есть ли в стандартной библиотеке Java что-нибудь еще, что могло бы помочь. Мой обычный инструмент выбора - java .util.Scanner, у которого есть хороший метод nextDouble (). Но Scanner работает с «токенами», поэтому nextDouble действительно означает «получить следующий токен и попытаться разобрать его как двойной». Токены разделены разделителями, которые по умолчанию являются пробелами. Так что у Scanner не будет проблем с "52 hi", но он не будет работать с "52hi". Теоретически, разделителем может быть любое регулярное выражение, которое я выберу, поэтому все, что мне нужно сделать, это составить регулярное выражение, которое при совпадении означает конец числа. Но это кажется даже труднее сделать, чем непосредственно писать регулярное выражение.
Я собирался расстаться с надеждой, когда нашел java .text.DecimalFormat, который явно говорит: «Я буду анализировать, насколько я может, и я скажу вам, как далеко я продвинулся, чтобы вы могли продолжать делать что-то еще с этого момента ". Но кажется, что он был в первую очередь предназначен для форматирования вещей для потребления человеком и, возможно, для анализа вещей, написанных машинами, а не для анализа вещей, написанных людьми, и это проявляется множеством маленьких способов. Например, он «поддерживает» нотацию scientifi c, например «1.2e1», но если вы используете ее, он будет настаивать на том, что число должно быть в нотации scientifi c, и не сможет выполнить синтаксический анализ, если вместо этого вы введете «12». Можно попытаться обойти эту проблему, проверив место, где произошел сбой, и проанализировав только материал до этого как число, но это подвержено ошибкам и даже более раздражает, чем просто написание регулярного выражения для чисел с плавающей точкой.
Тем временем в C, это будет просто sscanf ("% f"), и в C ++ вы можете использовать поток строк, чтобы делать в основном то же самое. Неужели нет эквивалента в Java?