3

スクリプト言語のインスタンスを新しい値Progress (n,m)に置き換える必要があります。Progress label="some text title" (n,m)(N,M)

N= integer ((n/m) * normal)
M= integer ( normal )

進行状況ステートメントは、スクリプト行のどこにあってもかまいません(さらに悪いことに、現在のスクリプトではありませんが、行に分割されます)。

normalは1から255までの指定された数値であり、n浮動m小数点数です。

これまでのところ、私のsed実装は以下のとおりです。それはフォーマットでのみ機能し、Progress (n,m)フォーマットでは機能しませんがProgress label="Title" (n,m)それは単なるナッツです:

#!/bin/bash
normal=$1; 
file=$2
for n in $(sed -rn '/Progress/s/Progress[ \t]+\(([0-9\. \t]+),([0-9\. \t]+)\).+/\1/p' "$file" )
do 
    m=$(sed -rn "/Progress/s/Progress[ \t]+\(${n},([0-9\. \t]+).+/\1/p" "$file")
    N=$(echo "($normal * $n)/$m" | bc)
    M=$normal
    sed -ri "/Progress/s/Progress[ \t]+\($n,$m\)/Progress ($N,$M)/" "$file"
done

簡単に言えば、これは機能しますが、より良い方法はありますか?

私のツールボックスにはsedスクリプトbashが含まれていますが、それほど多くはありませんperlawkこの問題の方が適していると思います。

サンプル入力を編集します。

Progress label="qt-xx-95" (0, 50) thermal label "qt-xx-95" ramp(slew=.75,sp=95,closed) Progress (20, 50) Pause  5 Progress (25, 50) Pause  5 Progress (30, 50) Pause  5 Progress (35, 50) Pause  5 Progress (40, 50) Pause  5 Progress (45, 50) Pause  5 Progress (50, 50)
Progress label="qt-95-70" (0, 40) thermal label "qt-95-70" hold(sp=70)        Progress (10, 40) Pause  5 Progress (15, 40) Pause  5 Progress (20, 40) Pause  5 Progress (25, 40) Pause  5 
4

3 に答える 3

1

awkは優れた分割機能を備えているため、この問題には適している可能性があります。

提供された入力に対して機能するソリューションを次に示します。これを と呼びましょうupdate_m_n_n.awk。bash で次のように実行しますawk -f update_m_n_n.awk -v normal=$NORMAL input_file

#!/usr/bin/awk

BEGIN {
  ORS = RS = "Progress"
  FS = "[)(]"
  if(normal == 0) normal = 10
}

NR == 1 { print }

length > 1 { 
  split($2, A, /, */)
  N = int( normal * A[1] / A[2] )
  M = int( normal )
  sub($2, N ", " M)
  print $0
}

説明

  • ORS = RS = "Progress": でセクションを分割し、出力Progressに含めProgressます。
  • FS = "[)(]": フィールドを括弧で区切ります。
  • NR == 1 { print }ORS:最初のセクションの前に挿入します。
  • split($2, A, /, */): の出現の間に括弧で囲まれたアイテムのみがあると仮定するとProgress、これは分割mnれてA配列になります。
  • sub($2, N ", " M)処置: 現在のレコードに新しい値を代入します。
于 2012-07-18T18:54:40.470 に答える
1

これはややもろいですが、うまくいくようですか?perl -pe を使用して 1 行に変更することもできますが、これはより明確だと思います。


use 5.16.0;
my $normal = $ARGV[0];
while(<STDIN>){
        s/Progress +(label=\".+?\")? *( *([0-9. ]+) *, *([0-9. ]+) *)/sprintf("Progress $1 (%d,%d)", int(($2/$3)*$normal),int($normal))/eg;
        print $_;
}

基本的な考え方は、オプションで $1 のラベル句をキャプチャし、n と m を $2 と $3 にキャプチャすることです。「e」修飾子を提供することにより、一致した文字列を評価されたコード片に置き換える perl の機能を使用します。label 句にエスケープされた引用符が含まれていたり、Progress トークンのようなものに一致する文字列が含まれていたりすると、劇的に失敗するため、理想的ではありません。n と m の弱い数の一致などの明らかな欠陥のいくつかを修正するためにこの正規表現を変更できますが、ここで誠実なパーサーが必要であることに同意します。

于 2012-07-18T19:31:05.127 に答える
0

私の最初の考えはsed、再帰的な置換 (tコマンド ) を試してみることでしたが、スタックするのではないかと思いました。

このperlコードは、複数行に分割されていないステートメントで機能する場合があります。複数の行にまたがる分割の場合、異なる行を結合するために別のプリプロセッサを作成するのがおそらく理にかなっています。

このコードは、"Progress" ステートメントを個別の行セグメントに分割し、置換ルールを適用してから、セグメントを 1 行に再結合して出力します。一致しない行は単純に印刷されます。一致するコードは後方参照を使用しているため、多少判読できなくなります。仕様が明確に見えなかったため、「通常の」パラメーターは浮動小数点値を取ることができると想定しました。

#!/usr/bin/perl -w

use strict;

die("Wrong arguments") if (@ARGV != 2);
my ($normal, $file) = @ARGV;
open(FILE, '<', $file) or die("Cannot open $file");

while (<FILE>) {
    chomp();
    my $line = $_;

    # Match on lines containing "Progress"
    if (/Progress/) {

        $line =~ s/(Progress)/\n$1/go;    # Insert newlines on which to split
        my @segs = split(/\n/, $line);    # Split line into segments containing possibly one "Progress" clause

        # Apply text-modification rules
        @segs = map {
            if (/(Progress[\s\(]+)([0-9\.]+)([\s,]+)([0-9\.]+)(.*)/) {
                my $newN = int($2/$4 * $normal);
                my $newM = int($normal);
                $1 . $newN . $3 . $newM . $5;
            } elsif (/(Progress\s+label="[^"]+"[\s\(]+)([0-9\.]+)([\s,]+)([0-9\.]+)(.*)/) {
                my $newN = int($2/$4 * $normal);
                my $newM = int($normal);
                $1 . $newN . $3 . $newM . $5;
            } else {
                $_;    # Segment doesn't contain "Progress"
            }
        } @segs;

        $line = join("", @segs);    # Reconstruct the single line
    }

    print($line,"\n");    # Print all lines
}
于 2012-07-18T18:54:47.147 に答える