Pregunta

Quiero poder escribir una función que reciba un número en notación científica como una cadena y separe el coeficiente y el exponente como elementos separados. Simplemente podría usar una expresión regular, pero el número entrante puede no estar normalizado y preferiría poder normalizar y luego dividir las partes.

Un colega tiene parte de una solución usando VB6 pero no está del todo, como lo muestra la transcripción a continuación.

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

debería haber sido 1 y 6

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

correct

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

correct

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

debe ser -1.233456 y -2

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

correct

¿Alguna idea? Por cierto, Clive es una CLI basada en VBScript y se puede encontrar en mi weblog .

¿Fue útil?

Solución

Google en " notación científica regexp " muestra un número de coincidencias, incluido este ( ¡no lo uses! ! ) que usa

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

que incluye casos como -.5e7 y + 00000e33 (los cuales es posible que no desee permitir).

En cambio, recomendaría altamente que use la sintaxis en el sitio web JSON de Doug Crockford que documenta explícitamente lo que constituye un número en JSON. Aquí está el diagrama de sintaxis correspondiente tomado de esa página:

 texto alternativo
(fuente: json.org )

Si mira la línea 456 de su json2.js script (conversión segura a / desde JSON en javascript), verá esta parte de una expresión regular:

/-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/

que, irónicamente, no coincide con su diagrama de sintaxis ... (parece que debería presentar un error) Creo que una expresión regular que implementa ese diagrama de sintaxis es esta:

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

y si desea permitir también un + inicial, obtendrá:

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

Agregue paréntesis de captura a su gusto.

También recomendaría encarecidamente que desarrolle un montón de casos de prueba, para asegurarse de incluir las posibilidades que desea incluir (o no incluir), como:

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

not allowed:
+0003   (leading zeros)
37.e88  (dot before the e)

¡Buena suerte!

Otros consejos

Partiendo de la respuesta mejor calificada, modifiqué un poco la expresión regular para que sea / ^ [+ \ -]? (? =.) (?: 0 | [1-9] \ d *)? ( ?: \. \ d *)? (?: \ d [eE] [+ \ -]? \ d +)? $ / .

Los beneficios que esto proporciona son:

  1. permite números coincidentes como .9 (hice el (?: 0 | [1-9] \ d *) opcional con ? )
  2. evita la coincidencia solo con el operador al principio y evita la coincidencia de cadenas de longitud cero (usa lookahead, (? =.) )
  3. evita la coincidencia de e9 porque requiere el \ d antes de la notación científica

Mi objetivo en esto es usarlo para capturar figuras significativas y hacer cálculos matemáticos significativos. Así que también voy a dividirlo con grupos de captura de la siguiente manera: /^[+\-font>?(?=.)(0|[1-9font>\d*)?(\.\d *)? (?: (\ d) [eE] [+ \ -]? \ d +)? $ / .

Una explicación de cómo obtener cifras significativas de esto:

  1. La captura completa es el número que puede entregar a parseFloat()
  2. Las coincidencias 1-3 se mostrarán como indefinidas o cadenas, por lo que combinarlas (reemplazar undefined 's con ' ') debería dar el número original del que se obtienen cifras significativas se puede extraer.

Esta expresión regular también evita la coincidencia de ceros con margen izquierdo, que JavaScript a veces acepta pero que he visto causar problemas y que no agrega nada a las cifras significativas, por lo que veo la prevención de ceros con margen izquierdo como un beneficio (especialmente en los formularios). Sin embargo, estoy seguro de que la expresión regular podría modificarse para engullir ceros con relleno izquierdo.

Otro problema que veo con esta expresión regular es que no coincidirá con 90.e9 u otros números similares. Sin embargo, considero que esto o coincidencias similares son altamente improbables ya que es la convención en notación científica evitar tales números. Aunque puede ingresarlo en JavaScript, puede ingresar fácilmente 9.0e10 y lograr las mismas cifras significativas.

UPDATE

En mis pruebas, también detecté el error de que podría coincidir con '.' . Por lo tanto, el look-ahead debe modificarse a (? = \. \ D | \ d) que conduce a la expresión regular final:

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

Aquí hay un código Perl que acabo de piratear juntos rápidamente.

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";
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top