有馬総一郎のブログ

(彼氏の事情)

2020年12月27日 16:29:55 JST - 3 minute read - Vim

Vim scriptで時分秒を秒に変換して、加算して書き換える

Audacityでラベル毎にファイル分割・変換するで、時分秒(h:mm:ss)を秒(s)に変換して加算して書き換える必要があったので、Vim Sriptでそんな変換ファンクションを実装してみた。

最初は、開始時刻、長さを表示しているのを、それぞれ秒に変換させるファンクションを作った。

0:00:00.000     0:02:03.081
0:02:03.081     0:04:45.451
0:06:48.533     0:04:15.588
0:11:04.121     0:05:50.975
0:16:55.097     0:06:37.438
function! s:MakeAudacityImportLabelTxtFile() range abort
  for i in range(1, line("$"))
    let strline = getline(i)
    let timeIn = matchlist(strline, '\(\d\):\(\d\{2\}\):\(\d\{2\}\)\.\(\d\{3\}\)', 0, 1)
    let length = matchlist(strline, '\(\d\):\(\d\{2\}\):\(\d\{2\}\)\.\(\d\{3\}\)', 0, 2)
    if len(timeIn) > 0 && len(length)
      let timeInMili = (timeIn[1]*3600 + timeIn[2]*60 + timeIn[3])*1000 + timeIn[4]
      let lengthMili = (length[1]*3600 + length[2]*60 + length[3])*1000 + length[4]
      let strLast = printf("%06s", timeInMili)
      let strNext = printf("%06s", timeInMili + lengthMili)
      let lastTrackTime = strpart(strLast, 0, len(strLast)-3) . '.' . strpart(strLast, len(strLast)-3) . '000'
      let nextTrackTime = strpart(strNext, 0, len(strNext)-3) . '.' . strpart(strNext, len(strNext)-3) . '000'
      call setline(i, lastTrackTime . "\t" . nextTrackTime . "\t". i)
    endif
  endfor
endfunction

これが↓になる

取り込みラベル編集ファイル1

000.000000	123.081000	1
123.081000	408.532000	2
408.533000	664.121000	3
664.121000	1015.096000	4
1015.097000	1412.535000	5

matchlistというメソッドを初めて使ったのだが、中々便利だ

echo matchlist('0:02:03.081', '\(\d\):\(\d\{2\}\):\(\d\{2\}\)\.\(\d\{3\}\)', 0, 1)

['0:02:03.081', '0', '02', '03', '081', '', '', '', '', '']

とリストとして取得できる。第4引数のcount指定で何番目に合致する文字列を取得するか指定できるのもありがたい。

echo matchlist('0:02:03.081     0:04:45.451', '\(\d\):\(\d\{2\}\):\(\d\{2\}\)\.\(\d\{3\}\)', 0, 2)

とパターンに一致する文字列が二つあっても、引数のcountを2に指定すれば

['0:04:45.451', '0', '04', '45', '451', '', '', '', '', '']

となる。

Vim scriptでは小数は、浮動小数点での扱いになるようなので、整数に変換してから、加算して、後で小数点を付けるという強引な方法にした。

Vim scriptでの数値から文字列はprintfを使うと便利なので、それを使った。今回は使わなかったが、文字列から数値に変換するときはstr2nrを使うようだ。

数値型 — 名無しのvim使い

そして、表示する文字列が準備できたら、それを現在の表示行と入れ替えるにはsetlineを使う。

それから、タブなどを文字列結合するときは"ダブルコーテーションで囲って、メタ文字を入力する。なので、この場合は. "\t" .とする。'だとそのままの文字として結合される。

と結構頑張ったのだけど、結局、 前回の記事で書いたように開始時刻、長さでマイクロ秒が丸めれているせいで、1ミリ秒ズレが生じる。

開始時刻から次の開始時刻までを長さとする方が良いと分かったので、そもそもの準備する文字列を開始時刻だけ1とすることにした。

0:02:03.081
0:06:48.533
0:11:04.121
0:16:55.097
0:23:32.536
function! s:MakeAudacityImportLabelTxtFile() range abort
  let lastTrackTime = '0.000000'
  for i in range(1, line("$"))
    let strline = getline(i)
    let timeIn = matchlist(strline, '\(\d\):\(\d\{2\}\):\(\d\{2\}\)\.\(\d\{3\}\)', 0, 1)
    if len(timeIn) > 0
      let nextTrackTime = printf("%s", timeIn[1]*3600 + timeIn[2]*60 + timeIn[3]) . '.' . timeIn[4] . '000'
      call setline(i, lastTrackTime . "\t" . nextTrackTime . "\t" . i)
      let lastTrackTime = nextTrackTime
    endif
  endfor
endfunction

とシンプルな形となった。この場合、↓のようになる。

取り込みラベル編集ファイル2

0.000000	123.081000	1
123.081000	408.533000	2
408.533000	664.121000	3
664.121000	1015.097000	4
1015.097000	1412.536000	5

こんな変換処理すらエディター内だけで完結できる Vim はやはり偉大だと改めて思った。


  1. 一番下の開始時刻は、ファイルの終了時刻を指定することとなる。 ↩︎

Tags: Vim

Audacityでラベル毎にファイル分割・変換する 2020年買った良かったもの