#java #kotlin
#java #kotlin
Вопрос:
У меня есть этот код на языке kotlin:
val stringDecimalvalue = ... // can come as '#,###.##' or '#.###,##' and the two are valid
Я хочу создать Double
с этим String
таким образом
var monetaryValue = Double(stringDecimalvalue)
Если значение находится в #,###.## Будет поднят формат a NumberFormatException
, тогда мне нужно знать этот шаблон перед форматированием.
Есть способ, при котором мне не нужно прокручивать всю строку или применять регулярное выражение с совпадением? (или, может быть, легкий подход с регулярными выражениями)
Спасибо!
Комментарии:
1. Просто выполните синтаксический анализ явно с обоими форматами. Вы могли бы написать свой собственный синтаксический анализатор, чтобы сделать его немного более эффективным, но я не могу представить, что это узкое место в любом приложении.
2. Как вы хотите проанализировать число, если вы не знаете, какой символ является десятичной точкой, а какой разделителем тысяч? Есть ли способ отличить одно от другого на основе формата, в котором находится число?
3. Я ожидал, что что-то вроде этого сработает @Voo
Double(DecimalFormat("0.#####").format("1,000.00"))
, но возвращает `IllegalArgumentException’, в котором говорится, что это недопустимое число4. Если сначала получить запятую, а затем точку, я знаю, что это в одном, а обратное верно для другого, но мне это не нравится, потому что мне нужно выполнить проверку других отсюда @DodgyCodeException
5. Как насчет такого числа, как
1.000
? Это тысяча или число от 1 до трех знаков после запятой? Если вы заранее не знаете, какой формат ожидать, будут некоторые числа, которые вы не сможете разобрать однозначно.
Ответ №1:
мне кажется, что самый простой способ найти последнее появление ,
or .
и удалить все появления .
и .
перед этим, тогда вы сможете использовать Double::parseString
Ответ №2:
Во-первых, я должен сказать, что не имеет смысла подход функции общего назначения propose без явного формата, потому что, как и комментарии @gidds и @DodgyCodeException, он подвержен двусмысленности.
Таким образом, я решаю проблему, используя regex
разделитель десятичных знаков, сгруппированный запятыми [0-9] (,[0-9]{3})*\.[0-9]{2}
, и перевернутый регистр [0-9] (\.[0-9]{3})*,[0-9]{2}
(разделитель запятой, сгруппированный точками). Затем уберите запятые и замените точки, чтобы получить десятичный формат без сгруппированных точек, который я хочу проанализировать Double
Я делаю это, как extension function
:
const val NOTHING = ""
const val COMMA = ","
const val POINT = "."
val commaGrouped = "[0-9] (,[0-9]{3})*\.[0-9]{2}".toRegex()
val pointGrouped = "[0-9] (\.[0-9]{3})*,[0-9]{2}".toRegex()
fun String.commaCleaned() = replace(COMMA, NOTHING)
fun String.pointCleaned() = replace(POINT, NOTHING)
fun String.commaToPoint() = replace(COMMA, POINT)
fun String.pointToComma() = replace(POINT, COMMA)
fun String.toDouble() =
when {
commaGrouped matches this -> Double(commaCleaned())
pointGrouped matches this -> Double(pointCleaned().commaToPoint())
else -> throw IllegalArgumentException(
"the value ${this} can't be converted to ${Double::class.java} "
"have match ${commaGrouped.pattern} "
"or ${pointGrouped.pattern}")
}
поймите, что целочисленный формат или точность более двух знаков после запятой не будут соответствовать для создания Double
, и это то, чего я тоже хочу.