1

科学数を 10 進数に置き換える試みの一環として、後方参照を文字列変数に保存したいのですが、うまくいきません。

私の入力ファイルは次のとおりです。

,8E-6,
,-11.78E-16,
,-17e+7,

次に、次を実行します。

open FILE, "+<C:/Perl/input.txt" or die $!;
open(OUTPUT, "+>C:/Perl/output.txt") or die;

while (my $lines = <FILE>){

  $find = "(?:,)(-?)(0|[1-9][0-9]*)(\.)?([0-9]*)?([eE])([+\-]?)([0-9]+)(?:,)";
  $noofzeroesbeforecomma = eval("$7-length($4)");
  $replace = '"foo $noofzeroesbeforecomma bar"';

  $lines =~ s/$find/$replace/eeg;
  print (OUTPUT $lines);
}

close(FILE);

私は得る

foo  bar
foo  bar
foo  bar

私が期待していた場所

foo 6 bar
foo 14 bar
foo 7 bar

$noofzeroesbeforecomma空または存在しないようです。

次の調整を行っても空の結果が得られます

$noofzeroesbeforecomma = $2;

置換文字列に直接挿入するだけ$2で何かが得られます (残念ながら、これは私が望むものではありません)。

誰でも助けることができますか?

私は Strawberry Perl (5.16.1.1-64bit) を 64 ビットの Windows 7 マシンで実行していますが、Perl の経験はまったくありません。

4

4 に答える 4

1

あなたの主な問題は使用していません

use strict;
use warnings;

warningsあなたに言っただろう

Use of uninitialized value $7 in concatenation (.) or string at ...
Use of uninitialized value $4 in concatenation (.) or string at ...

自分でハックしようとするのではなく、指数表記を処理できるモジュールを試してみることをお勧めします。

コードは、作業順序で次のようになります。ご覧のとおり、前に評価されて存在するq()ことを避けるために、eval 文字列を囲みました。eval の double eval はやや過剰なので、eval 自体も削除しました。$7$4

use strict;
use warnings;

while (my $lines = <DATA>) {
    my $find="(?:,)(-?)(0|[1-9][0-9]*)(\.)?([0-9]*)?([eE])([+\-]?)([0-9]+)(?:,)";
    my $noof = q|$7-length($4)|;
    $lines =~ s/$find/$noof/eeg;
    print $lines;
}


__DATA__
,8E-6,
,-11.78E-16,
,-17e+7,

出力:

6
14
7

ちなみに、使わないstrictのは面倒です。のような変数名を使用しながら行うと、$noofzeroesbeforecommaタイプミスが発生しやすいため、2 倍の手間がかかります。

于 2012-09-07T14:37:36.013 に答える
0

これは後方参照ではなく、元の問題であり、数値を科学的記数法から変換します。これが失敗する場合があると確信しています。

#!/usr/bin/env perl

use strict;
use warnings;
use bignum;

for (<DATA>) {
    next unless /([+-]?\d+(?:\.\d+)?)[Ee]([+-]\d+)/;
    print $1 * 10 ** $2 . "\n";
}

__DATA__
,8E-6,
,-11.78E-16,
,-17e+7,

出力:

0.000008
-0.000000000000001178
-170000000
于 2012-09-07T15:26:43.600 に答える
0

問題は、Perl がこれらすべてのタイプの式を処理できることです。また、Perl のデータの標準項目は文字列であるため、式を取得するだけで使用できます。したがって、次の式を使用します。

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

sprintfボロディンが示したように、周囲のテキストからそれを抽出し、それをフォーマットするために使用します。

しかし、それがあなたがやろうとしたことのより良いケースを見るのに役立つなら、これはよりうまくいきます

my ( $whole, $frac, $expon )
    = $line =~ m/(?:,)-?(0|[1-9]\d*)(?:\.(\d*))?[eE]([+\-]?\d+)(?:,)/
    ;
my $num = $expon - length( $frac );
  • とにかく指数で符号をキャプチャしないのはなぜですか?それで算術を行う場合は?

  • キャプチャに名前を付けて、eval不要な場合は避けることをお勧めします。

  • この置換は、そのままではあまり意味がありません。

  • 実際、記号も数字も大文字と小文字を区別できない(?i)ため、先頭に a を置き、 E "文字クラス" を避け[Ee]ます。

    /((?i)-?\d+(?:.\d+)?e[+-]?\d+)/
    
于 2012-09-07T20:35:26.123 に答える
0

Regexp::Common::numberモジュールのプラグインを使用することをお勧めします。Regexp::Commonこれにより、すべての実数が検出され、指数マーカーを持つものを置き換えることができます

このコードはアイデアを示しています。オプションを使用-keepすると、モジュールは各コンポーネントを$N変数の 1 つに入れます。指数マーカー -eまたはE- は に$7あるため、これが存在するかどうかに応じて数値を変換できます

use strict;
use warnings;

use Regexp::Common;

my $real_re = $RE{num}{real}{-keep};

while (<>) {
  s/$real_re/ $7 ? sprintf '%.20f', $1 : $1 /eg;
  print;
}

出力

入力例を考えると、このコードは以下を生成します。値は、置換で追加のコードを使用してさらに整理できます

,0.00000800000000000000,
,-0.00000000000000117800,
,-170000000.00000000000000000000,
于 2012-09-07T15:31:24.033 に答える