最近Vimでよくやるパースの方法
function! s:parse_args(q_args) "{{{ let modes = '' let options = '' let lhs = '' let rhs = '' try let rest = a:q_args let rest = s:skip_white(rest) let [modes , rest] = s:parse_modes(rest) let rest = s:skip_white(rest) let [options , rest] = s:parse_options(rest) let rest = s:skip_white(rest) let [lhs, rest] = s:parse_lhs(rest) let rest = s:skip_white(rest) let [rhs, rest] = s:parse_rhs(rest) "if rest != '' " throw 'error' "endif catch echoerr 'error' endtry return [modes, options, lhs, rhs, rest] endfunction "}}}
だいたい
[パースした結果とか, 残りの文字列]
のような感じで残りの文字列を処理していく感じ。
それぞれの関数は正規表現で処理するなり手続き的に処理するなりいろいろと。
厳格にパースするならthinca/vim-vparsec · GitHubみたいなParsec風ライブラリ作って処理するなりすればいいんじゃないですかね。
おまけ
ユーティリティ関数晒してみる。
function! s:skip_white(q_args) "{{{ return substitute(a:q_args, '^\s*', '', '') endfunction "}}} function! s:parse_one_arg_from_q_args(q_args) "{{{ let arg = s:skip_white(a:q_args) let head = matchstr(arg, '^.\{-}[^\\]\ze\([ \t]\|$\)') let rest = strpart(arg, strlen(head)) return [head, rest] endfunction "}}} function! s:eat_n_args_from_q_args(q_args, n) "{{{ let rest = a:q_args for _ in range(1, a:n) let rest = s:parse_one_arg_from_q_args(rest)[1] endfor let rest = s:skip_white(rest) " for next arguments. return rest endfunction "}}}
s:skip_white()は単純に先頭の空白を削除する関数。
s:parse_one_arg_from_q_args()は.vimrcの中でもよく使う関数で、
単純な引数のフォーマットの場合なら単に
必要に応じて'や"で囲んだ文字列を自作Exコマンドに渡したい場合に
:MyExCommand foo 'my string' bar
のように起動すると
["foo", "'my", "string'", "bar"]
な感じで分断されて残念な感じになるためにパースが必要になる。*1
ユーティリティ関数はこれからもいろいろ.vimrcに追加していくと思う。