Разумно разбирать научную нотацию?
-
10-07-2019 - |
Вопрос
Я хочу иметь возможность написать функцию, которая получает число в научной нотации в виде строки и выделяет из него коэффициент и показатель степени как отдельные элементы.Я мог бы просто использовать регулярное выражение, но входящий номер может быть не нормализован, и я бы предпочел иметь возможность нормализовать, а затем разделить части.
Коллега частично нашел решение с использованием VB6, но это не совсем так, как показано в приведенной ниже расшифровке.
cliVe> a = 1e6
cliVe> ? "coeff: " & o.spt(a) & " exponent: " & o.ept(a)
coeff: 10 exponent: 5
должно было быть 1 и 6
cliVe> a = 1.1e6
cliVe> ? "coeff: " & o.spt(a) & " exponent: " & o.ept(a)
coeff: 1.1 exponent: 6
правильный
cliVe> a = 123345.6e-7
cliVe> ? "coeff: " & o.spt(a) & " exponent: " & o.ept(a)
coeff: 1.233456 exponent: -2
правильный
cliVe> a = -123345.6e-7
cliVe> ? "coeff: " & o.spt(a) & " exponent: " & o.ept(a)
coeff: 1.233456 exponent: -2
должно быть -1.233456 и -2
cliVe> a = -123345.6e+7
cliVe> ? "coeff: " & o.spt(a) & " exponent: " & o.ept(a)
coeff: 1.233456 exponent: 12
правильный
Есть какие-нибудь идеи?Кстати, Clive - это CLI, основанный на VBScript, и его можно найти на моем блог.
Решение
Google на " научное обозначение regexp " показывает число совпадений, включая этот ( не используйте его !!! ! ) который использует
*** warning: questionable ***
/[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/
, который включает в себя такие случаи, как -.5e7 и + 00000e33 (оба из которых вы не можете разрешить).
Вместо этого я бы настоятельно рекомендовал вам использовать синтаксис на сайте JSON Дуга Крокфорда a> который явно документирует, что составляет число в JSON. Вот соответствующая синтаксическая диаграмма, взятая с этой страницы:
(источник: json.org )
Если вы посмотрите на строку 456 его json2.js скрипт (безопасное преобразование в / из JSON в javascript), вы увидите эту часть регулярного выражения:
/-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/
который, по иронии судьбы, не соответствует его синтаксической диаграмме .... (похоже, я должен сообщить об ошибке) Я считаю, что регулярное выражение, которое реализует эту синтаксическую диаграмму, является следующим:
/-?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?/
и если вы хотите разрешить начальный +, вы получите:
/[+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?/
Добавьте захватывающие скобки по своему вкусу.
Я также настоятельно рекомендую вам детализировать несколько тестовых случаев, чтобы убедиться, что вы включаете те возможности, которые вы хотите включить (или не включать), такие как:
allowed:
+3
3.2e23
-4.70e+9
-.2E-4
-7.6603
not allowed:
+0003 (leading zeros)
37.e88 (dot before the e)
Удачи!
Другие советы
Основываясь на ответе с самым высоким рейтингом, я немного изменил регулярное выражение, чтобы оно было /^[+\-]?(?=.)(?:0|[1-9]\d*)?(?:\.\d*)?(?:\d[eE][+\-]?\d+)?$/
.
Преимущества, которые это дает, заключаются в следующем:
- позволяет сопоставлять такие числа, как
.9
(Я сделал(?:0|[1-9]\d*)
опционально с?
) - предотвращает сопоставление только оператора в начале и предотвращает сопоставление строк нулевой длины (использует предварительный просмотр,
(?=.)
) - предотвращает совпадение
e9
потому что для этого требуется\d
перед научной нотацией
Моя цель в этом - использовать его для получения значимых цифр и выполнения значимых математических расчетов.Поэтому я также собираюсь разделить его на группы захвата следующим образом: /^[+\-]?(?=.)(0|[1-9]\d*)?(\.\d*)?(?:(\d)[eE][+\-]?\d+)?$/
.
Объяснение того, как получить значимые цифры из этого:
- Весь снимок - это номер, который вы можете передать кому-либо
parseFloat()
- Совпадения 1-3 будут отображаться как неопределенные или строки, поэтому объедините их (замените
undefined
"это с''
) должен указывать исходное число, из которого могут быть извлечены значимые цифры.
Это регулярное выражение также предотвращает сопоставление нулей с заполнением слева, которое JavaScript иногда принимает, но которое, как я видел, вызывает проблемы и которое ничего не добавляет к значимым цифрам, поэтому я рассматриваю предотвращение нулей с заполнением слева как преимущество (особенно в формах).Тем не менее, я уверен, что регулярное выражение можно было бы изменить, чтобы оно поглощало нули с дополнением слева.
Еще одна проблема, которую я вижу с этим регулярным выражением, заключается в том, что оно не будет совпадать 90.e9
или другие подобные числа.Тем не менее, я нахожу это или подобные совпадения крайне маловероятными, поскольку в научной нотации принято избегать таких чисел.Хотя вы можете ввести его в JavaScript, вы можете так же легко ввести 9.0e10
и добиться таких же значительных показателей.
Обновить
В ходе моего тестирования я также обнаружил ошибку, которой это могло соответствовать '.'
.Таким образом, прогноз на будущее должен быть изменен следующим образом (?=\.\d|\d)
что приводит к окончательному регулярному выражению:
/^[+\-]?(?=\.\d|\d)(?:0|[1-9]\d*)?(?:\.\d*)?(?:\d[eE][+\-]?\d+)?$/
Вот некоторый Perl-код, который я быстро взломал.
my($sign,$coeffl,$coeffr,$exp) = $str =~ /^\s*([-+])?(\d+)(\.\d*)?e([-+]?\d+)\s*$/;
my $shift = length $coeffl;
$shift = 0 if $shift == 1;
my $coeff =
substr( $coeffl, 0, 1 );
if( $shift || $coeffr ){
$coeff .=
'.'.
substr( $coeffl, 1 );
}
$coeff .= substr( $coeffr, 1 ) if $coeffr;
$coeff = $sign . $coeff if $sign;
$exp += $shift;
say "coeff: $coeff exponent: $exp";