Question

Je veux pouvoir écrire une fonction qui reçoit un nombre en notation scientifique sous forme de chaîne et en sépare le coefficient et l'exposant en tant qu'éléments séparés. Je pourrais simplement utiliser une expression régulière, mais le nombre entrant ne sera peut-être pas normalisé et je préférerais pouvoir normaliser puis décomposer les parties.

Un collègue a en partie trouvé une solution utilisant VB6 mais ce n’est pas tout à fait là, comme le montre la transcription ci-dessous.

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

aurait dû être 1 et 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

devrait être -1,233456 et -2

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

correct

Des idées? A propos, Clive est une CLI basée sur VBScript et se trouve sur mon weblog .

Autres conseils

En me basant sur la réponse la mieux notée, j’ai légèrement modifié l’expression rationnelle pour qu'elle soit / ^ [+ \ -]? (? =.) (?: 0 | [1-9] \ d *)? ( ?: \. \ d *)? (?: \ d [eE] [+ \ -]? \ d +)? $ / .

Les avantages offerts sont les suivants:

  1. permet de faire correspondre des nombres tels que .9 (j'ai rendu le (?: 0 | [1-9] \ d *) facultatif avec ? )
  2. empêche d'apparier l'opérateur au début et les chaînes de longueur nulle (utilise lookahead, (? =.) )
  3. empêche la correspondance e9 car il nécessite le \ d avant la notation scientifique

Mon objectif à cet égard est de l’utiliser pour capturer des chiffres significatifs et effectuer des calculs significatifs. Donc, je vais aussi le séparer en capturant des groupes comme suit: / ^ [+ \ -]? (? =.) (0 | [1-9] \ d *)? (\. \ D *)? (?: (\ d) [eE] [+ \ -]? \ d +)? $ / .

Une explication sur la façon d’obtenir des chiffres significatifs:

  1. La capture complète est le numéro que vous pouvez remettre à parseFloat ()
  2. Les correspondances 1 à 3 apparaîtront sous forme de chaîne ou de caractère non défini. Par conséquent, si vous les combinez (remplacez les indéfinis par '' ) devrait donner le numéro d'origine à partir duquel les chiffres significatifs peut être extrait.

Cette expression rationnelle empêche également la correspondance des zéros remplis à gauche, ce que JavaScript accepte parfois, mais que j'ai rencontré des problèmes et qui n'ajoute rien aux chiffres significatifs. Je considère donc que la prévention des zéros remplacés à gauche est un avantage (en particulier dans les formulaires). Cependant, je suis sûr que l'expression régulière pourrait être modifiée pour engloutir des zéros remplis à gauche.

Un autre problème que je vois avec cette regex est qu'elle ne correspondra pas à 90.e9 ou à d'autres numéros similaires. Cependant, j'estime que cette correspondance ou des correspondances similaires est hautement improbable, car c'est la convention en notation scientifique d'éviter de tels nombres. Bien que vous puissiez le saisir en JavaScript, vous pouvez tout aussi bien saisir 9.0e10 et obtenir les mêmes chiffres significatifs.

MISE À JOUR

Lors de mes tests, j'ai également remarqué l'erreur de correspondance entre '.' . Par conséquent, la prévision doit être modifiée en (? = \. \ D | \ d) , ce qui conduit à la regex finale:

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

Voici un code Perl que je viens de pirater rapidement.

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";
scroll top