5

今日、正規表現を使用して特定の名前のファイル内の特定のコンテンツを追跡し、そのコンテンツを削除してから置換を追加する、非常に小さな Ruby スクリプトを作成しました。(そうしないと、反復中に問題が発生する可能性があります)。

私は ruby​​ にあまり慣れていません (1 ~ 2 週間前に休暇の仕事が始まってから使用しているだけです) が、私の習慣の 1 つは、リスト (またはインデックスを使用している他のほとんどの ADT) に触れないようにすることです。特定のコンテンツを削除するには)、使用している言語は関係ありません。

Arrayいくつかの検索の後、私は役立ついくつかの機能を見つけました。現在、私は使用してArray.reject!おり、スクリプトは機能したいように機能しArray.reject! {|line| line =~ regex }ますが、配列内のオブジェクトをスキップすることに問題がない理由が正直にわかりません。これらのソース、ruby -docsおよびいくつかのランダムな Web サイトは、反復中に変更が即座に適用されることを確認します。\nもちろん、次のものはそれ自体の行になります(ただし、それは文字列の最後の部分にすぎません)。

誰かがこれについて素晴らしい説明をしましたか?

4

2 に答える 2

14

Array#reject!forループを使用して、配列の要素を反復処理します。Cコードは次のとおりです。

for (i = 0; i < RARRAY_LEN(ary); ) {
  VALUE v = RARRAY_PTR(ary)[i];
  if (RTEST(rb_yield(v))) {
    rb_ary_delete_at(ary, i);
    result = ary;
  } 
  else {
    i++;
  }
}

興味深い部分は、ステートメントiでインクリメントされていないことです。forに指定されたブロックが現在の要素にreject!評価される場合、true削除され、ary[i]自動的に次の要素を指します。と評価された場合にのみfalseiがインクリメントされます。

[a b c d].reject! {|x| x == b}

 0 <------- i # doesn't match => i++
[a b c d]

   1 <----- i # matches => delete ary[i]
[a b c d]

   1 <----- i # doesn't match => i++
[a c d]

     2 <--- i # doesn't match => finished
[a c d]
于 2012-07-13T10:47:43.807 に答える
2

ary_reject_bangの C 実装の心臓部であるのソース コードを次に示しreject!ます。

static VALUE
ary_reject_bang(VALUE ary)
{
    long i;
    VALUE result = Qnil;

    rb_ary_modify_check(ary);
    for (i = 0; i < RARRAY_LEN(ary); ) {
        VALUE v = RARRAY_PTR(ary)[i];
        if (RTEST(rb_yield(v))) {
            rb_ary_delete_at(ary, i);
            result = ary;
        }
        else {
            i++;
        }
    }
    return result;
}

RARRAY_PTRで定義されているマクロruby.hで、Ruby 配列の基になる C 配列にアクセスできます。実際の削除は で行われrb_ary_delete_at、他のマクロを使用して配列を整理します。

VALUE
rb_ary_delete_at(VALUE ary, long pos)
{
    long len = RARRAY_LEN(ary);
    VALUE del;

    if (pos >= len) return Qnil;
    if (pos < 0) {
        pos += len;
        if (pos < 0) return Qnil;
    }

    rb_ary_modify(ary);
    del = RARRAY_PTR(ary)[pos];
    MEMMOVE(RARRAY_PTR(ary)+pos, RARRAY_PTR(ary)+pos+1, VALUE,
        RARRAY_LEN(ary)-pos-1);
    ARY_INCREASE_LEN(ary, -1);

    return del;
}
于 2012-07-13T10:31:03.270 に答える