6

テキスト行の 3 つのグループをインターレースしようとしています。たとえば、次のテキスト:

a
a
a
b
b
b
c
c
c

は次のように変換されます:

a
b
c
a
b
c
a
b
c

これを行う効率的な方法はありますか?

4

5 に答える 5

6

~/.vim私のファイルの深さのどこかに、:Interleaveコマンドがあります(以下に追加)。引数:Interleaveがなければ、通常どおりインターリーブします。2 つの引数を使用して、グループ化する数を指定します。たとえば:Interleave 2 1、上から 2 行を取り、下から 1 行とインターリーブします。

今あなたの問題を解決するために

:1,/c/-1Interleave
:Interleave 2 1
  • 1,/c/-1最初の行で始まり、文字に一致する最初の行の 1 行上で終わる範囲c
  • :1,/c/-1Interleave基本的にabのグループをインターリーブします。
  • :Interleave 2 1今回の範囲はファイル全体です。
  • :Interleave 2 1aとが混在するグループをbのグループとインターリーブしcます。2対1の混合比で。

:Interleaveコードは以下です。

command! -bar -nargs=* -range=% Interleave :<line1>,<line2>call Interleave(<f-args>)
fun! Interleave(...) range
  if a:0 == 0
    let x = 1
    let y = 1
  elseif a:0 == 1
    let x = a:1
    let y = a:1
  elseif a:0 == 2
    let x = a:1
    let y = a:2
  elseif a:0 > 2
    echohl WarningMsg
    echo "Argument Error: can have at most 2 arguments"
    echohl None
    return
  endif
  let i = a:firstline + x - 1
  let total = a:lastline - a:firstline + 1
  let j = total / (x + y) * x + a:firstline
  while j < a:lastline
    let range = y > 1 ? j . ',' . (j+y) : j
    silent exe range . 'move ' . i
    let i += y + x
    let j += y
  endwhile
endfun
于 2013-02-11T00:37:41.590 に答える
1

ある場合はxclip、行を切り取り、pasteそれらをインターリーブするために使用できます。

  1. 1 セットの行を視覚的に選択する
  2. 入力"+dしてクリップボードに切り取ります
  3. 他の行のセットを視覚的に選択します
  4. タイプ!paste -d '\n' /dev/stdin <(xclip -o -selection clipboard)
于 2016-10-04T21:32:51.817 に答える
1

I just ran into this issue independently tonight. Mine's not as elegant as some of the answers, but it's easier to understand I think. It makes many assumptions, so it's a bit of a hack:

  • A) It assumes there's some unique character (or arbitrary character string) not present in any of the lines - I assume @ below.
  • B) It assumes you don't want leading or trailing white space in any of the a, b, or c sections.
  • C) It assumes you can easily identify the maximum line length, and then pad all lines to be that length (e.g. perhaps using %! into awk or etc., using printf)

    1. Pad all lines with spaces to the same maximum length.
    2. Visual Select just the a and b sections, then %s/$/@
    3. Block copy and past the b section to precede the c section.
    4. Block copy and paste the a section to precede the bc section.
    5. %s/@/\r
    6. %s/^ *//g
    7. %s/ *$//g
    8. delete the lines left where the a and b sections were.
于 2013-05-26T05:07:35.383 に答える
1

これは「ワンライナー」です(ほぼ)が、一意の行ごとに1を引いて、例では2回やり直す必要があります。役に立たないかもしれませんが、VIM のパターンについて学ぶ良い練習になったと思います。行全体が一意である限り、すべての種類の行を処理します (例:mnomnp2 つの一意の行)。

最初にこれを確認してください(そして、行内の何かまたは他のものにマップされていません):/

:set nowrapscan

次に、たとえばこれらをマップします(再帰的である必要があります nnoremap) 。文字どおりに入力する必要があり
<C-R>ます。in pattern は「非常に魔法の」、否定的な先読みを意味します。2 番目の括弧内にあるものを使用します。<CR>
\v@!\2

:nmap ,. "xy$/\v^<C-R>x$<CR>:/\v^(<C-R>x)@!(.*)$\n(\2)$/m-<CR>j,.
:nmap ,, gg,.

次に、必要な,,回数、例では2回実行します。すべてbの に 1 つ、すべての に 1 つc


編集:マッピングの説明。このマッピングで 1 回実行されたかのように、質問の例を使用します。
1 回の実行後:

1. a
2. b
3. a
4. b
5. a
6. b
7. c
8. c
9. c

カーソルは最後a(5 行目) にあり、 と入力する,,と、まず最初の行に戻り、次に のマッピングを実行します,.。そのマッピングは次 のように実行されます。

"xy$             # yanks current line (line 1) to reg. "x" ("a")  "
/\v^<C-R>x$<CR>  # finds next line matching reg. "x" ("a" at line 3)
:/\v^(<C-R>x)@!(.*)$\n(\2)$/m-<CR>
# finds next line that have a copy under it ("c" in line 7) and moves that line
# to current line (to line 3, if no "-" #after "m" it's pasted after current line)
# Parts in the pattern:
- ^(<C-R>x)@!(.*)$  # matches next line that don't start with what's in reg. "x"
- \n(\2)$           # ...and followed by newline and same line again ("c\nc")
- m-<CR>            # inserts found line at current line (line 3)
j                # down one line (to line 4, where second "a" now is)
,.               # does all again (recursive), this time finding "c" in line 8
...
,.               # gives error since there are no more repeated lines,
                 # and the "looping" breaks.
于 2013-02-11T14:55:56.403 に答える