Analizowanie notacji naukowej sensownie?

Chcę być w stanie napisać funkcję, która otrzymuje liczbę w notacji naukowej jako ciąg i dzieli z niej Współczynnik i wykładnik jako oddzielne pozycje. Mógłbym po prostu użyć wyrażenia regularnego, ale liczba przychodząca może nie być znormalizowana i wolałbym być w stanie normalizować, a następnie rozbijać części.

Kolega ma częściowo sposób rozwiązania przy użyciu VB6, ale to nie do końca tam, jak pokazuje poniższy zapis.

cliVe> a = 1e6
cliVe> ? "coeff: " & o.spt(a) & " exponent: " & o.ept(a)
coeff: 10 exponent: 5 

powinno być 1 and 6

cliVe> a = 1.1e6
cliVe> ? "coeff: " & o.spt(a) & " exponent: " & o.ept(a)
coeff: 1.1 exponent: 6

poprawne

cliVe> a = 123345.6e-7
cliVe> ? "coeff: " & o.spt(a) & " exponent: " & o.ept(a)
coeff: 1.233456 exponent: -2

poprawne

cliVe> a = -123345.6e-7
cliVe> ? "coeff: " & o.spt(a) & " exponent: " & o.ept(a)
coeff: 1.233456 exponent: -2

powinno być -1.233456 i -2

cliVe> a = -123345.6e+7
cliVe> ? "coeff: " & o.spt(a) & " exponent: " & o.ept(a)
coeff: 1.233456 exponent: 12

poprawne

Jakieś pomysły? Przy okazji, Clive jest CLI opartym na VBScript i można go znaleźć na moim blogu .
Author: Chad Birch, 2009-03-12

3 answers

Google na "scientific notation regexp" pokazuje liczbę dopasowań, w tym Ten (nie używaj go!!!!), który wykorzystuje

*** warning: questionable ***
/[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/

Który obejmuje przypadki takie jak -.5e7 i + 00000e33 (oba mogą nie chcieć).

Zamiast tego, ja wysoce zalecam użycie składni na stronie Douga Crockforda JSON , która jawnie dokumentuje to, co stanowi liczbę w JSON. Oto odpowiedni schemat składni wzięty z ta strona:

Alt text http://www.json.org/number.gif

Jeśli spojrzysz na linię 456 jego json2.skrypt js (bezpieczna konwersja do / Z JSON w javascript), zobaczysz tę część wyrażenia regularnego:

/-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/
Co, jak na ironię, nie pasuje do jego diagramu składni.... (wygląda na to, że powinienem zgłosić błąd) uważam, że regexp, który implementuje ten diagram składni, to ten:
/-?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?/

I jeśli chcesz zezwolić na inicjał +, to get:

/[+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?/

Dodaj nawiasy przechwytywania do swoich upodobań.

Gorąco polecam również kilka przypadków testowych, aby upewnić się, że uwzględniasz te możliwości, które chcesz włączyć (lub nie włączyć), takie jak:

allowed:
+3
3.2e23
-4.70e+9
-.2E-4
-7.6603

not allowed:
+0003   (leading zeros)
37.e88  (dot before the e)
Powodzenia!
 66
Author: Jason S,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-18 15:07:23

Oto kod Perla, który szybko zhakowałem.

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";
 1
Author: Brad Gilbert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-18 04:01:56

Bazując na najwyżej ocenianej odpowiedzi, zmodyfikowałem nieco regex na /^[+\-]?(?=.)(?:0|[1-9]\d*)?(?:\.\d*)?(?:\d[eE][+\-]?\d+)?$/.

Korzyści, jakie daje to:

  1. pozwala dopasować liczby takie jak .9 (zrobiłem (?:0|[1-9]\d*) opcjonalnie z ?)
  2. zapobiega dopasowywaniu tylko operatora na początku i zapobiega dopasowywaniu ciągów o zerowej długości (używa lookahead, (?=.))
  3. zapobiega dopasowaniu e9, ponieważ wymaga \d przed notacją naukową

Moim celem w tym jest aby użyć go do przechwytywania znaczących liczb i wykonywania znaczących obliczeń. Więc zamierzam również pokroić go z przechwytywania grup takich jak tak: /^[+\-]?(?=.)(0|[1-9]\d*)?(\.\d*)?(?:(\d)[eE][+\-]?\d+)?$/.

Wyjaśnienie, jak uzyskać znaczące liczby z tego:

  1. cały uchwyt jest liczbą, którą możesz podać parseFloat()
  2. dopasowania 1-3 będą wyświetlane jako undefined lub strings, więc ich połączenie (zastąp undefined's przez '') powinno dać liczbę pierwotną, z której mogą być znaczące liczby / align = "left" /

Ten regex zapobiega również dopasowywaniu zer lewych, które JavaScript czasami akceptuje, ale które widziałem powodować problemy i które nie dodaje nic do znaczących liczb, więc widzę zapobieganie zer lewych jako korzyść (szczególnie w formularzach). Jednak, jestem pewien, że regex można zmodyfikować, aby pożerać lewe wyściełane zera.

Kolejny problem widzę z tym regex jest to, że nie będzie pasować 90.e9 lub inne tego typu numery. Jednak uważam, że to lub podobne pasuje bardzo mało prawdopodobne, ponieważ jest to konwencja w notacji naukowej, aby uniknąć takich liczb. Chociaż można go wprowadzić w JavaScript, można równie łatwo wprowadzić 9.0e10 i osiągnąć te same znaczące liczby.

UPDATE

W moich testach złapałem również błąd, który może pasować '.'. Tak więc spojrzenie w przyszłość powinno być zmodyfikowane do (?=\.\d|\d), co prowadzi do ostatecznego wyrażenia regularnego:

/^[+\-]?(?=\.\d|\d)(?:0|[1-9]\d*)?(?:\.\d*)?(?:\d[eE][+\-]?\d+)?$/
 1
Author: Troy Weber,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-10 19:47:04