Размышление о научной нотации разумно?
Я хочу иметь возможность написать функцию, которая получает число в научной нотации в виде строки и отделяет от нее коэффициент и показатель как отдельные элементы. Я мог бы просто использовать регулярное выражение, но входящий номер не может быть нормализован, и я предпочел бы нормализовать, а затем сломать части.
У коллеги есть часть пути решения, использующего 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, и его можно найти в моем weblog.
Ответы
Ответ 1
Google на "научная нотация regexp" показывает ряд совпадений, в том числе этот (не используйте его!!!!), который использует
*** warning: questionable ***
/[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/
который включает в себя такие случаи, как -.5e7 и + 00000e33 (оба из которых вы не можете разрешить).
Вместо этого я бы высоко рекомендовал использовать синтаксис на сайте Doug Crockford JSON, который явно документирует, что представляет собой номер в JSON. Здесь соответствующая синтаксическая диаграмма, взятая с этой страницы:
alt text http://www.json.org/number.gif
Если вы посмотрите на строку 456 своего json2.js script (безопасное преобразование в/из 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)
Удачи!
Ответ 2
Вот код 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";
Ответ 3
/^[+\-]?(?=.)(?:0|[1-9]\d*)?(?:\.\d*)?(?:\d[eE][+\-]?\d+)?$/
наивысший рейтинг, я немного изменил регулярное выражение, чтобы быть /^[+\-]?(?=.)(?:0|[1-9]\d*)?(?:\.\d*)?(?:\d[eE][+\-]?\d+)?$/
.
Это дает следующие преимущества:
- позволяет сопоставлять числа, такие как
.9
(я сделал .9
((?:0|[1-9]\d*)
с ?
) - предотвращает совпадение только оператора в начале и предотвращает совпадение строк нулевой длины (использует lookahead,
(?=.)
) - предотвращает совпадение
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+)?$/