2

複数のバックスペース文字 ( ^H) を含むファイルがあります。これらのバックスペースを perl 内で「適用」できるようにしたいと考えています。いくつかの解決策を見つけましたが、私の場合はどれもうまくいきませんでした。重要な行は次のとおりです。

test>>M^H ^HManagement.^H^H^H^H^H^H^H^H^H^Hanagement.F^H ^HFiles.^H^H^H^H^Hiles.s^H ^Hs.^H ^Hc^H ^H^H ^Hscript.^H ^H^H^H^H^Hripts^H ^H^H ^H^H ^H^H ^H^H ^H^H ^H^H ^Hscripts.^H.s^H ^Hshow_file ^H^H^H^H^H^H^H^H^Hhow_file = transform_factory_to_running^M

結果は次のようになります。

test>>Management.Files.scripts.show_file = transform_factory_to_running^M

https://stackoverflow.com/a/1298728/2837411で提案されているように、vi内でテキストを正しく変換できます。しかし、この質問でも提案されているperlソリューション: https://stackoverflow.com/a/1298970/2837411はうまくいきませんでした(を使用 $_):

s{([^\x08]+)(\x08+)}{substr$1,0,-length$2}eg;

この出力は次のとおりです。

test>>Management.Files.sscriptriptscripts.show_file = transform_factory_to_running^M

すべてのバックスペースが消えましたが、それらのいくつかが別のバックスペースに適用されているように見えますか?!

4

2 に答える 2

2

これは単純に置換のループで行われます

行頭のバックスペース (効果がない場合) またはバックスペース以外の文字とそれに続くバックスペース (前の文字の削除をエミュレート) のすべてのインスタンスを繰り返し削除します。

後者はこのコンテキストでは単語境界アンカーであるため、正規表現パターン内の\cH代わりに使用する必要があったことに注意してください\b

use strict;
use warnings;
use v5.10;

my $s = 'M^H ^HManagement.^H^H^H^H^H^H^H^H^H^Hanagement.F^H ^HFiles.^H^H^H^H^Hiles.s^H ^Hs.^H ^Hc^H ^H^H ^Hscript.^H ^H^H^H^H^Hripts^H ^H^H ^H^H ^H^H ^H^H ^H^H ^H^H ^Hscripts.^H.s^H ^Hshow_file ^H^H^H^H^H^H^H^H^Hhow_file = transform_factory_to_running^M';
$s =~ s/\^H/\b/g; # convert `^H` to backspace

1 while $s =~ s/(?:^|[^\cH])\cH//g;

say $s;

出力

Management.Files.scripts.show_file = transform_factory_to_running^M

アップデート

これは、文字列を文字のストリームとして処理するバージョンです。simbabque のソリューションに似ていますが、代わりに左から右に進みます

基本的に、バックスペースは、削除する文字がある$result場合、バッファの末尾から文字を削除しますが、他の文字は単に追加されます

出力は上記のコードと同じです

use strict;
use warnings;
use v5.10;

my $s = 'M^H ^HManagement.^H^H^H^H^H^H^H^H^H^Hanagement.F^H ^HFiles.^H^H^H^H^Hiles.s^H ^Hs.^H ^Hc^H ^H^H ^Hscript.^H ^H^H^H^H^Hripts^H ^H^H ^H^H ^H^H ^H^H ^H^H ^H^H ^Hscripts.^H.s^H ^Hshow_file ^H^H^H^H^H^H^H^H^Hhow_file = transform_factory_to_running^M';
$s =~ s/\^H/\b/g;

say apply_backspace_characters($s);

sub apply_backspace_characters {

  my $result;

  for my $c ( split //, shift ) {
    if ( $c eq "\b" ) {
      substr($result, -1) = '';
    }
    else {
      $result .= $c;
    }
  }

  $result;
}
于 2015-08-03T14:24:39.620 に答える
0

これは、おそらく最速ではない非常に明示的なソリューションです。しかし、それは仕事を成し遂げます。

sub apply_backspace_characters {
    my $string = shift;

    # replace the ^H characters with one BS char
    $string =~ s/\^H/chr(8)/ge;

    my @output;
    my $backspace_count = 0; # keep track of how many BS we have seen in a row

    # iterate over string by char from the right
    foreach my $char ( reverse split //, $string ) {
        if ( $char eq chr(8) ) {
            # it's a backspace, increase counter and skip
            $backspace_count++;
            next;
        }
        if ($backspace_count) {
            # there are still backspaces on the 'stack', decrease counter and skip
            $backspace_count--;
            next;
        }
        # no backspaces left, keep this character and put at front
        # (because we are going backwards)
        unshift @output, $char;
    }

    return join '', @output;
}

say apply_backspace_characters(
    "test>>M^H ^HManagement.^H^H^H^H^H^H^H^H^H^Hanagement.F^H ^HFiles.^H^H^H^H^Hiles.s^H ^Hs.^H ^Hc^H ^H^H ^Hscript.^H ^H^H^H^H^Hripts^H ^H^H ^H^H ^H^H ^H^H ^H^H ^H^H ^Hscripts.^H.s^H ^Hshow_file ^H^H^H^H^H^H^H^H^Hhow_file = transform_factory_to_running^M"
);

これにより、以下が出力されます。

test>>Management.Files.scripts.show_file = transform_factory_to_running^M
于 2015-08-03T09:32:29.267 に答える