1
-- Converts tabs to spaces
function detab(text)
    local tab_width = 4
    local function rep(match)
        local spaces = -match:len()
        print("match:"..match)
        while spaces<1 do spaces = spaces + tab_width end
        print("Found "..spaces.." spaces")
        return match .. string.rep(" ", spaces)
    end
    text = text:gsub("([^\n]-)\t", rep)
    return text
end


str='   thisisa string'
--thiis is a      string

print("length: "..str:len())
print(detab(str))
print(str:gsub("\t","    "))

タブをスペースに変換するmarkdown.luaからのこのコードがあります(その名前が示すように)。
私がなんとか理解したのは、文字列の先頭からタブが見つかるまで検索し、一致した部分文字列を'rep'関数に渡すことです。一致するものがなくなるまで、これを繰り返します。
私の問題は、特にwhileループでrep関数が何をしているのかを理解しようとすることです。
ループが で停止するのはなぜ1ですか?
なぜカウントアップするのですか?.
驚いたことに、文字列内のスペースの数を数えますが、正確には謎です。
その出力を最後のgsub置換からの出力と比較すると、それらが異なることがわかります。
Detab は文字の配置を維持しますが、gsub置換は維持しません。どうしてこんなことに?
ボーナス質問。Scite で空白をオンにすると、 の前の't'タブが 3 番目の の前のタブよりも長いことがわかります's'なぜ違うのですか?

4

2 に答える 2

4

関数を分析するとrep、これが実行しているように見えます。まず、渡された一致文字列の長さを取り、それを負にします (たとえば、-1 を掛けるなど)。while ループでは、正になるまでスペースを追加し続けます。

数直線を使用してこれを視覚化する方が簡単かもしれません:

<--|----|-------|----|----|----|----|----|----|----|----|--->
  -n      -spaces             -2   -1    0    1    2    n

本質的に、ループは「オーバーフロー」する前にスペースに収まる「tab_width」の数を計算しようとしています。ここでは、0 から 1 への遷移をカットオフ ポイントとして使用しています。ループ後、spacesどれだけオーバーフローしたかが表示されます。

実際、while ループは、モジュロとして知られている数学演算を模倣しています。つまり、内部rep関数は次のように書き直すことができます。

local function rep(match)
  local spaces = tab_width - match:len() % tab_width

  return match .. string.rep(" ", spaces)
end

これは、すべてのタブ文字を無差別str:gsub("\t", " ")に 4つのスペースに置き換える outter とは異なります。OTOH、関数では、タブ文字を置き換えるスペースの数は、一致するキャプチャの長さに依存します。detab

eg.
matching length is 1, replace tab with 3 spaces
matching length is 2, replace tab with 2 spaces
matching length is 3, replace tab with 1 space
matching length is n, replace tab with tab_width - (n % tab_width) spaces
etc.
于 2013-07-31T22:06:17.310 に答える
1

おまけの質問に答えるには: タブ文字はタブストップに揃えます。タブストップは 8 文字です。最初のタブは 6 列目から始まるため、3 つのスペースを埋め込む必要があります。2 番目のタブは 16 列目から始まるため、必要なスペースは 1 つだけです。

スペースが正の数になると、ループは停止します。これは、一致するテキストよりも長くなるのに十分なスペースが得られるまで、ループが「インデント」単位でスペースを追加しているためです。次に、その数のスペースを一致したテキストと組み合わせると、正しいタブストップにパディングされた文字列が作成されます。

それがgsubが異なる理由でもあります。gsub は、タブをタブストップ文字としてではなく、4 つのスペースとして扱っています。したがって、2 番目のタブはタブストップまでパディングされず、代わりに 4 つのスペースに拡張されます。

于 2013-07-31T19:36:08.020 に答える