-
Notifications
You must be signed in to change notification settings - Fork 65
/
Copy patheval.jax
10286 lines (8894 loc) · 485 KB
/
eval.jax
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
*eval.txt* For Vim バージョン 8.0. Last change: 2017 Jan 28
VIMリファレンスマニュアル by Bram Moolenaar
Vim script *expression* *expr* *E15* *eval*
Vim script の利用についてはユーザーマニュアルの41章|usr_41.txt|でも解説され
ている。
注意: Vim script はコンパイル時に無効化できる。もしそうなっているとこのド
キュメントに書かれている事は有効ではない。|+eval|と|no-eval-feature|を参照。
1. 変数 |variables|
1.1 変数の型
1.2 関数への参照 |Funcref|
1.3 リスト |Lists|
1.4 辞書 |Dictionaries|
1.5 変数について補足 |more-variables|
2. 式の文法 |expression-syntax|
3. 内部変数 |internal-variables|
4. 組み込み関数 |functions|
5. 関数定義 |user-functions|
6. 波括弧{}変数 |curly-braces-names|
7. コマンド |expression-commands|
8. 例外処理 |exception-handling|
9. 例 |eval-examples|
10. +eval機能が無効 |no-eval-feature|
11. サンドボックス |eval-sandbox|
12. テキストロック |textlock|
13. テスト |testing|
{Vi にはこれらのコマンドはない}
==============================================================================
1. 変数 *variables*
1.1 変数の型 ~
*E712*
変数には9種類の型がある:
数値 32ビットまたは64ビットの符号有整数。|expr-number| *Number*
64ビット数値は |+num64| 機能つきでコンパイルされたときのみ有効。
例: -123 0x10 0177 0b1011
浮動小数点数 浮動小数点数。|floating-point-format| *Float*
{|+float| 機能つきでコンパイルされたときのみ}
例: 123.456 1.15e-6 -1.1e3
文字列 終端がNUL文字である8ビットの符号無し文字(バイト)。
|expr-string| 例: "ab\txx\"--" 'x-z''a,c'
リスト 要素の順序つきの列 |List|。
例: [1, 2, ['a', 'b']]
辞書 順序を持たない連想配列: 各要素はキーと値を持つ。|Dictionary|
例: {'blue': "#0000ff", 'red': "#ff0000"}
Funcref 関数への参照 |Funcref|。
例: function("strlen")
辞書や引数とバインドすることができ、そのときは部分適用(Partial)
のように働く。
例: function("Callback", [arg], myDict)
特殊値 |v:false|, |v:true|, |v:none| と |v:null|。 *Special*
ジョブ ジョブに使われる。|job_start()|を参照。 *Job* *Jobs*
チャンネル チャンネルに使われる。|ch_open()|を参照。 *Channel* *Channels*
数値と文字列は文脈に応じて相互に変換される。
数値から文字列への変換は数字のASCII表現によって行われる。例:
数値 123 --> 文字列 "123" ~
数値 0 --> 文字列 "0" ~
数値 -1 --> 文字列 "-1" ~
*octal*
文字列から数値への変換は最初の数字を用いて数値に変換する。16進表記 "0xf9" や
8進表記 "017"、2進数表記の "0b10" も認識される。文字列が数字で始まらない場合結
果は0となる。例:
文字列 "456" --> 数値 456 ~
文字列 "6bar" --> 数値 6 ~
文字列 "foo" --> 数値 0 ~
文字列 "0xf1" --> 数値 241 ~
文字列 "0100" --> 数値 64 ~
文字列 "0b101" --> 数値 5 ~
文字列 "-8" --> 数値 -8 ~
文字列 "+8" --> 数値 0 ~
文字列を強制的に数値に変換するには0を足す: >
:echo "0100" + 0
< 64 ~
先頭の0によって8進数とみなされるのを防いだり、異なる基数を使うには|str2nr()|を
使う。
*TRUE* *FALSE*
ブール(真理値)演算には数値が使われる。0は偽を意味し、非0は真を表す。また、
|v:false| と |v:true| を使うこともできる。関数から真が返されたときは数値の 1
であり、偽が返されたときは数値の 0 である。
Note 次のコマンドをみると >
:if "foo"
:" 実行されない
"foo" は 0 に変換され、それは偽を意味する。もし文字列がゼロでない数値から始ま
る場合は真を意味する: >
:if "8foo"
:" 実行される
文字列が空ではないか調べるためには empty() を使用して次のようにする。 >
:if !empty("foo")
<
*non-zero-arg*
関数の引数は、|TRUE| とは少し異なる場合がある: 引数が存在し、それが非ゼロの
Number、|v:true| または空でない String に評価される場合、値は TRUE と見なされ
る。" " と "0" も空文字列ではないので、モードをクリアするのに注意すること。
List、Dictionary、または Float は数値または文字列ではないため、FALSE と評価さ
れる。
*E745* *E728* *E703* *E729* *E730* *E731* *E908* *E910* *E913*
リスト、辞書、Funcref、ジョブ、チャンネルは自動的に変換されない。
*E805* *E806* *E808*
数値と浮動小数点数をまぜると浮動小数点数になる。それ以外には浮動小数点数への自
動的な変換は存在しない。文字列から浮動小数点数へは str2float() を使い、浮動小
数点数から文字列へは printf() を、浮動小数点数から数値へは float2nr() を使う。
*E891* *E892* *E893* *E894* *E907* *E911* *E914*
浮動小数点数が予期されているところでは数値も使用可能だが、それ以外は使用できな
い。
*no-type-checking*
変数の型を変更しようとしてもエラーは発生しない。
1.2 関数への参照 ~
*Funcref* *E695* *E718*
関数への参照は、関数|function()|、関数|funcref()|またはラムダ式|expr-lambda|を
使うことで得られる。関数への参照は、式の中で関数名が要求される場所で使うと参照
先の関数を呼び出す。例: >
:let Fn = function("MyFunc")
:echo Fn()
< *E704* *E705* *E707*
関数参照の変数名は、大文字、"s:"、"w:"、"t:"、"b:" のいずれかで始めなければな
らない。"g:" も使えるが、あとに続く名前は大文字で始めなければならない。関数参
照と参照先の関数の名前を同じにすることはできない。
関数を定義して、それへの参照を直接辞書に入れるための特別な形式がある。例: >
:function dict.init() dict
: let self.val = 0
:endfunction
この辞書のキーは小文字で始めなければならない。実際の関数名はここでは使われない。
|numbered-function|も参照。
|:call|コマンドでも関数参照を使うことができる: >
:call Fn()
:call dict.init()
参照先の関数名は|string()|で得られる。 >
:let func = string(Fn)
|call()|を使うと、リスト型の変数を引数として関数参照を呼び出すことができる: >
:let r = call(Fn, mylist)
<
*Partial*
関数参照は、辞書および/もしくは引数とバインドすることができる。これは部分適用
(Partial)とも呼ばれる。これは、辞書および/もしくは引数を function() または
funcref() に渡すことで作成される。その関数を呼び出すと、その辞書および/もしく
は引数がその関数に渡される。例: >
let Cb = function('Callback', ['foo'], myDict)
call Cb()
これは、関数を以下のようにして呼び出す: >
call myDict.Callback('foo')
これは関数を何かに渡す場合、例えば |ch_open()| の引数とする場合などに非常に有
用である。
Note 関数の辞書へのバインドは、その関数が辞書のメンバーであるときにも発生する
ことに注意: >
let myDict.myFunction = MyFunction
call myDict.myFunction()
ここで、MyFunction() は myDict を "self" として受け取る。これは、"myFunction"
メンバーがアクセスされたときに起こる。"myFunction" を別の辞書 otherDict に代入
して呼び出すと、それは otherDict にバインドされる: >
let otherDict.myFunction = myDict.myFunction
call otherDict.myFunction()
今度は、"self" は "otherDict" になる。しかし、辞書を明示的にバインドしたときに
はこれは起こらない: >
let myDict.myFunction = function(MyFunction, myDict)
let otherDict.myFunction = myDict.myFunction
call otherDict.myFunction()
ここでは、"self" は "myDict" である。なぜなら明示的にバインドされているからで
ある。
1.3 リスト ~
*list* *List* *Lists* *E686*
リストとは順序を保つ要素の列である。要素はどんな型でもよい。要素へはインデック
ス番号を使ってアクセスする。列の任意の位置に要素を追加したり削除することができ
る。
リストの作成 ~
*E696* *E697*
リストを作るには、[]の中にコンマで区切って要素を書く。
例: >
:let mylist = [1, two, 3, "four"]
:let emptylist = []
要素はどんな式でもよい。要素としてリストを指定すると、リストのリストができる:
>
:let nestlist = [[11, 12], [21, 22], [31, 32]]
最後の要素の後に余分なコンマがあると無視される。
リストのインデックス ~
*list-index* *E684*
リストの要素にアクセスするには、リスト名の後に[]を書き、その中にインデックスを
書く。インデックスは0基点(つまり最初の要素のインデックスは0)である。 >
:let item = mylist[0] " 最初の要素(1)を取得
:let item = mylist[2] " 3番目の要素(3)を取得
取得した要素がリストならば、さらに続けてインデックスを書くことができる: >
:let item = nestlist[0][1] " 最初のリストの2番目の要素(12)を取得
<
負のインデックスを指定すると、リストの末尾から数えられる。インデックス-1は最後
の要素を示し、-2は最後から2番目を指す >
:let last = mylist[-1] " 最後の要素("four")を取得
無効なインデックスによるエラーを回避するには関数|get()|を使う。するとインデッ
クスが無効な場合は、0かまたは自分で指定した既定値が返る: >
:echo get(mylist, idx)
:echo get(mylist, idx, "NONE")
リストの連結 ~
2つのリストを連結するには演算子 "+" を使う: >
:let longlist = mylist + [5, 6]
:let mylist += [7, 8]
1個の要素を先頭または末尾に付け加えるには、[]で囲んでリストにして連結する。リ
ストの特定の要素を変更するには後述の|list-modification|を参照。
部分リスト ~
*sublist*
リストの一部分を取り出すには、[]の中に始点と終点のインデックスを書き、コロンで
区切る: >
:let shortlist = mylist[2:-1] " リスト[3, "four"]を得る
始点のインデックスを省略すると0となる。終点のインデックスを省略すると-1となる >
:let endlist = mylist[2:] " 2番目から最後まで: [3, "four"]
:let shortlist = mylist[2:2] " 1個の要素からなるリスト: [3]
:let otherlist = mylist[:] " リストのコピーを作る
終点のインデックスが始点のインデックスよりも前になってしまった場合は空リストと
なる。エラーメッセージは表示されない。
終点のインデックスがリストの長さより大きい場合は、長さ-1を指定したときと同じに
なる: >
:let mylist = [0, 1, 2, 3]
:echo mylist[2:8] " 結果: [2, 3]
NOTE: mylist[s:e]と書くと変数 "s:e" をインデックスとして使ったと解釈される。
":" の前に1文字の変数を使うときは十分注意すること。必要ならこのようにスペース
を入れるとよい: mylist[s : e].
リストの同一性 ~
*list-identity*
変数 "aa" がリストであり、それを別の変数 "bb" に代入したとすると、両方とも同じ
変数を参照するようになる。よってリスト "aa" を変更すると "bb" も変更される: >
:let aa = [1, 2, 3]
:let bb = aa
:call add(aa, 4)
:echo bb
< [1, 2, 3, 4]
リストのコピーを作るには関数|copy()|を使う。前述の通り[:]を使ってもできる。こ
れは浅いコピーである。つまりリストの要素であるリストに変更を加えると、コピーさ
れたリスト内の同じ要素も変更される: >
:let aa = [[1, 'a'], 2, 3]
:let bb = copy(aa)
:call add(aa, 4)
:let aa[0][1] = 'aaa'
:echo aa
< [[1, aaa], 2, 3, 4] >
:echo bb
< [[1, aaa], 2, 3]
完全に独立したコピーを作るには|deepcopy()|を使う。これは再帰的にリストの要素の
コピーを作る。ただし深さは100レベルまでである。
2つの変数が同じリストを指しているかは演算子 "is" で判定できる。"isnot" はその
逆である。一方、"==" は2つのリストが同じ値を持っているかを判定する。 >
:let alist = [1, 2, 3]
:let blist = [1, 2, 3]
:echo alist is blist
< 0 >
:echo alist == blist
< 1
Note リストの比較について注意: 2つのリストは、同じ長さを持ち、全要素が "==" の
意味で等しいとき、等しいとみなされる。ただ、1つ例外がある: 数値と文字列を比較
するとそれらは異なるとみなされる。変数に対して "==" で比較したときに行われるよ
うな自動的な型変換は行われない。例: >
echo 4 == "4"
< 1 >
echo [4] == ["4"]
< 0
つまり、リストの比較は数値や文字列の比較よりも厳格である。単純な値もリストに入
れることによりこの方法で比較することができる: >
:let a = 5
:let b = "5"
:echo a == b
< 1 >
:echo [a] == [b]
< 0
リストのアンパック ~
リストの要素を個々の変数としてアンパックするには、[]の中に変数を書く: >
:let [var1, var2] = mylist
変数の個数とリストの要素数が一致しないときはエラーになる。リストにある余分な要
素をまとめて受け取るには、";" と受け取る変数名を書いておく: >
:let [var1, var2; rest] = mylist
上の例は次とほぼ同じである: >
:let var1 = mylist[0]
:let var2 = mylist[1]
:let rest = mylist[2:]
要素が 2 つしかないときでもエラーにはならない。"rest" は空リストになる。
リストの変更 ~
*list-modification*
リストの中の特定の要素を変更するには次のように|:let|を使う: >
:let list[4] = "four"
:let listlist[0][3] = item
始点と終点を指定してリストの一部分を変更することができる。代入する値は、少なく
とも削除する範囲の要素数と同じ数だけ必要である: >
:let list[3:5] = [3, 4, 5]
リストに要素を追加したり削除するには関数を使う。いくつか例を示す: >
:call insert(list, 'a') " 先頭に要素 'a' を挿入する
:call insert(list, 'a', 3) " 要素 'a' をlist[3]の前に挿入する
:call add(list, "new") " 文字列の要素を最後に追加する
:call add(list, [1, 2]) " 1個の要素としてリストを追加する
:call extend(list, [1, 2]) " 2個の要素からなるリストを連結する
:let i = remove(list, 3) " 要素3を削除する
:unlet list[3] " 同上
:let l = remove(list, 3, -1) " 要素3から最後までを削除する
:unlet list[3 : ] " 同上
:call filter(list, 'v:val !~ "x"') " 要素 'x' を削除
要素の順番を変更する: >
:call sort(list) " リストをアルファベット順にソート
:call reverse(list) " 要素の順序を反転させる
:call uniq(sort(list)) " ソートして重複を削除する
for ループ ~
|:for|ループは、1つの変数に対してリストの各要素を順番に代入し、コマンドを実行
していく。例: >
:for item in mylist
: call Doit(item)
:endfor
上の例は次と同じ: >
:let index = 0
:while index < len(mylist)
: let item = mylist[index]
: :call Doit(item)
: let index = index + 1
:endwhile
やりたいことがリストの各要素を変更するだけなら、forループを使うより関数|map()|
を使った方がよりシンプルになる。
|:let|コマンドと同じように、|:for|は変数のリストをループ変数にすることができる。
この場合、引数はリストのリストでなければならない。 >
:for [lnum, col] in [[1, 3], [2, 8], [3, 0]]
: call Doit(lnum, col)
:endfor
これはリストの各要素に対して|:let|コマンドを実行するかのように実行される。また
この場合も引数の型は全て同じでないとエラーになる。
引数の残りを1個のリスト変数に代入することもできる: >
:for [i, j; rest] in listlist
: call Doit(i, j)
: if !empty(rest)
: echo "remainder: " . string(rest)
: endif
:endfor
リスト操作関数 ~
*E714*
以下はリスト操作に使える関数である: >
:let r = call(funcname, list) " 引数リストをつけて関数を呼び出す
:if empty(list) " リストが空かどうか判定する
:let l = len(list) " リストの要素数
:let big = max(list) " リスト中の最大値
:let small = min(list) " リスト中の最小値
:let xs = count(list, 'x') " 'x' の出現回数を数える
:let i = index(list, 'x') " 最初に 'x' が現れる位置のインデックス
:let lines = getline(1, 10) " バッファから10行を取得
:call append('$', lines) " バッファに行を追加する
:let list = split("a b c") " 文字列を分割してリストにする
:let string = join(list, ', ') " リストの要素を連結して文字列にする
:let s = string(list) " リストの文字列表現
:call map(list, '">> " . v:val') " 各要素の前に ">> " をつける
機能を組み合わせると、処理を単純に記述できることを覚えておくとよい。例えば、リ
スト中の全ての数値の和を求める例: >
:exe 'let sum = ' . join(nrlist, '+')
1.4 辞書 ~
*dict* *Dictionaries* *Dictionary*
辞書とは連想配列である。各要素はキーと値を持つ。要素はキーによって特定できる。
要素は特に順序を持たずに保持される。
辞書の作成 ~
*E720* *E721* *E722* *E723*
辞書を作るには、{}の中にコンマで区切って要素を書く。各要素のキーと値はコロンで
区切る。それぞれのキーは1度しか現れてはならない。例: >
:let mydict = {1: 'one', 2: 'two', 3: 'three'}
:let emptydict = {}
< *E713* *E716* *E717*
キーは必ず文字列である。数値を使うこともできるが、自動的に文字列に変換される。
よって文字列 '4' のキーと数値4のキーは同一の要素を参照する。
Note 文字列 '04' と数値04は異なることに注意。なぜなら数値04は文字列 '4' に変換
されるからである。空文字列もキーとして使用できる。
値はどんな式でもよい。辞書を値にすると、ネストした辞書ができる: >
:let nestdict = {1: {11: 'a', 12: 'b'}, 2: {21: 'c'}}
最後の要素の後に余分なコンマがあると無視される。
要素にアクセスする ~
通常、要素にアクセスするには[]の中にキーを書く: >
:let val = mydict["one"]
:let mydict["four"] = 4
また、この書き方で既存の辞書に要素を追加できる。この点はリストと異なる。
キー名がアルファベット、数字、アンダースコアだけからなる場合は、以下の形式が使
える|expr-entry|: >
:let val = mydict.one
:let mydict.four = 4
要素はリストや辞書を含むどんな型でもよいため、インデックス参照とキー参照を続け
て書くことができる: >
:echo dict.key[idx].key
辞書からリストへの変換 ~
辞書の全要素に対してループを行いたい場合がある。そのためには辞書をリストに変換
し、そのリストに対して|:for|ループを行う。
多くの場合はキーに対してループを行う。これには関数|keys()|を使う: >
:for key in keys(mydict)
: echo key . ': ' . mydict[key]
:endfor
このキーのリストはソートされていない。ソートさせるには関数|sort()|を使う: >
:for key in sort(keys(mydict))
値に対してループを行うには関数|values()|を使う: >
:for v in values(mydict)
: echo "value: " . v
:endfor
キーと値両方を得るには関数|items()|を使う。この関数は、キーと値の2個の要素から
なるリストのリストを返す: >
:for [key, value] in items(mydict)
: echo key . ': ' . value
:endfor
辞書の同一性 ~
*dict-identity*
辞書のコピーを作るにはリストと同様に|copy()|と|deepcopy()|を使う必要がある。そ
うでなく代入を行うと同一の辞書を参照するようになる: >
:let onedict = {'a': 1, 'b': 2}
:let adict = onedict
:let adict['a'] = 11
:echo onedict['a']
11
2つの辞書は、全てのキー・値のペアが等しいとき等しいとみなされる。より詳しくは
|list-identity|を参照。
辞書の変更 ~
*dict-modification*
辞書の要素を変更したり、新しい要素を追加するには|:let|を使う: >
:let dict[4] = "four"
:let dict['one'] = item
辞書から要素を取り除くには|remove()|か|:unlet|を使う。以下のように辞書からキー
"aaa" を取り除くには3つの方法がある: >
:let i = remove(dict, 'aaa')
:unlet dict.aaa
:unlet dict['aaa']
2つの辞書を併合させるには|extend()|を使う: >
:call extend(adict, bdict)
上のコマンドはbdictの全ての要素をadictに追加する。キーが重複した要素はbdictの
要素により上書きされる。この動作は3番目の引数により変更できる。
Note 辞書の要素間に順序は定まっていない。そのため ":echo adict" としたとき、も
ともとadictにあった要素が先に、bdictから追加された要素が後に表示されると考えて
はならない。
辞書から条件を指定して要素を取り除くには|filter()|が使える: >
:call filter(dict, 'v:val =~ "x"')
このコマンドは "dict" から 'x' にマッチしない要素を全て取り除く。
関数を辞書に入れる ~
*Dictionary-function* *self* *E725* *E862*
関数が "dict" 属性つきで定義されると、特殊な方法で呼び出すことができる。例: >
:function Mylen() dict
: return len(self.data)
:endfunction
:let mydict = {'data': [0, 1, 2, 3], 'len': function("Mylen")}
:echo mydict.len()
これはオブジェクト指向プログラミングのメソッドに似ている。この辞書の要素は
|Funcref|である。暗黙に定義されるローカル変数 "self" は、この関数を呼び出した
辞書を参照している。
"dict" 属性をつけないでFuncrefを辞書に入れることもできる。しかしその場合、変
数 "self" は定義されない。
*numbered-function* *anonymous-function*
関数に名前をつける必要をなくすために、関数を定義して直接辞書に代入することがで
きる: >
:let mydict = {'data': [0, 1, 2, 3]}
:function mydict.len()
: return len(self.data)
:endfunction
:echo mydict.len()
こうすると関数に番号がふられ、dict.lenがこの関数を参照する|Funcref|となる。こ
の関数は|Funcref|を通してのみ呼び出せる。参照している|Funcref|がなくなると、こ
の関数は自動的に削除される。
番号付き関数には "dict" 属性を付ける必要はない。
番号付き関数でエラーが発生したときは、あるトリックを使うことで発生源を確認でき
る。例えば 42 という関数なら次のようにする: >
:function {42}
辞書操作関数 ~
*E715*
以下は辞書操作に使える関数である: >
:if has_key(dict, 'foo') " 辞書がキー "foo" の要素を持つなら真
:if empty(dict) " 辞書が空なら真
:let l = len(dict) " 辞書の要素数
:let big = max(dict) " 辞書中の最大値
:let small = min(dict) " 辞書中の最小値
:let xs = count(dict, 'x') " 'x' の出現回数を数える
:let s = string(dict) " 辞書の文字列表現
:call map(dict, '">> " . v:val') " 各要素の前に ">> " をつける
1.5 変数について補足 ~
*more-variables*
変数や式の結果の型を知りたいのならば、関数|type()|を使う。
オプション 'viminfo' にフラグ '!' が含まれるならば、大文字で始まり小文字を含ま
ない名前のグローバル変数は、viminfoファイル|viminfo-file|に格納される。
オプション 'sessionoptions' が "global" を含むなら、大文字で始まり少なくとも一
文字以上の小文字を含む名前のグローバル変数は、sessionファイル|session-file|に
格納される。
変数名 何処に保存されるか ~
my_var_6 されない
My_Var_6 sessionファイル
MY_VAR_6 viminfoファイル
波括弧を使って変数名を構成できる。詳細は|curly-braces-names|を参照。
==============================================================================
2. 式の文法 *expression-syntax*
式文法一覧、優先順位の低いものから高い順に:
|expr1| expr2
expr2 ? expr1 : expr1 if-then-else 条件式
|expr2| expr3
expr3 || expr3 .. 論理和
|expr3| expr4
expr4 && expr4 .. 論理積
|expr4| expr5
expr5 == expr5 等しい
expr5 != expr5 等しくない
expr5 > expr5 より大きい
expr5 >= expr5 大きいか等しい
expr5 < expr5 より小さい
expr5 <= expr5 小さいか等しい
expr5 =~ expr5 正規表現にマッチする
expr5 !~ expr5 正規表現にマッチしない
expr5 ==? expr5 文字列として等しい(大文字/小文字区別無し)
expr5 ==# expr5 文字列として等しい(大文字/小文字区別有り)
etc. 上記の各式は大小文字の区別を、?を付加すると行
わず、#を付加すると行う
expr5 is expr5 同一の |List| のインスタンス
expr5 isnot expr5 異なる |List| のインスタンス
|expr5| expr6
expr6 + expr6 .. 足し算またはリストの連結
expr6 - expr6 .. 引き算
expr6 . expr6 .. 文字列の連結
|expr6| expr7
expr7 * expr7 .. 掛け算
expr7 / expr7 .. 割り算
expr7 % expr7 .. 剰余(割った余り)
|expr7| expr8
! expr7 論理否定
- expr7 単項のマイナス {訳注: -1等}
+ expr7 単項のプラス
|expr8| expr9
expr8[expr1] 文字列のバイト、またはリストの要素
expr8[expr1 : expr1] 文字列の部分文字列、またはリストの部分リスト
expr8.name 辞書 |Dictionary| の要素
expr8(expr1, ...) |Funcref| 変数による関数呼び出し
|expr9| number 数定数
"string" 文字列定数。バックスラッシュは特別な意味を持つ
'string' リテラル文字列定数。'を含めるには2重にする
[expr1, ...] リスト |List|
{expr1: expr1, ...} 辞書 |Dictionary|
&option オプション変数
(expr1) 式の入れ子
variable 内部変数
va{ria}ble 波括弧付きの内部変数
$VAR 環境変数
@r レジスタ 'r' の値
function(expr1, ...) 関数呼出し
func{ti}on(expr1, ...) 波括弧付きの内部変数
{args -> expr1} ラムダ式
".." はその演算が、その後に他の演算を続ける事ができることを示している。
例: >
&nu || &list && &shell == "csh"
一つのレベルにある全ての式は左から右に解釈される。
expr1 *expr1* *E109*
-----
expr2 ? expr1 : expr1
'?' より前の式は数値として評価される。その結果が|TRUE|であった場合、'?' と ':'
に挟まれた式の値がこの式全体の値となり、そうでなかった場合は ':' 以降の式の値
が全体の値となる。
例: >
:echo lnum == 1 ? "先頭" : lnum
始めの式が "expr2" であるから、そこに別の?:を含むことはできない。残り二つの式
については以下のように再帰的な?:の利用が許される。
例: >
:echo lnum == 1 ? "top" : lnum == 1000 ? "last" : lnum
読み易くするために、行継続|line-continuation|を利用することが推奨される: >
:echo lnum == 1
:\ ? "top"
:\ : lnum == 1000
:\ ? "last"
:\ : lnum
':' の前には必ずスペースを入れること。そうでないと "a:1" のような変数の使用と
間違えてしまう可能性がある。
expr2 and expr3 *expr2* *expr3*
---------------
expr3 || expr3 .. 論理和 *expr-barbar*
expr4 && expr4 .. 論理積 *expr-&&*
演算子 "||" と "&&" は左右に一つずつ引数を取る。引数は数値に変換される。結果は:
入力 出力 ~
n1 n2 n1 || n2 n1 && n2 ~
|FALSE| |FALSE| |FALSE| |FALSE|
|FALSE| |TRUE| |TRUE| |FALSE|
|TRUE| |FALSE| |TRUE| |FALSE|
|TRUE| |TRUE| |TRUE| |TRUE|
演算子は続けて書く事ができる。例: >
&nu || &list && &shell == "csh"
Note "&&" は "||" よりも高い優先順位を持っている。これは次の事を意味する: >
&nu || (&list && &shell == "csh")
結果が確定した時点で残りの式は省略され、解釈されない。これはC言語で行われるこ
とに似ている。例: >
let a = 1
echo a || b
これはaが|TRUE|であるため、変数bが宣言されていなくても有効であり、結果は絶対
に|TRUE|である。次のも同様に: >
echo exists("b") && b == "yes"
これもbが宣言されているいないに関わらず有効である。後半の項はbが定義されている
時にだけ評価される。
expr4 *expr4*
-----
expr5 {cmp} expr5
2つの式expr5を比較し、結果が偽なら0を、真なら1を返す。
*expr-==* *expr-!=* *expr->* *expr->=*
*expr-<* *expr-<=* *expr-=~* *expr-!~*
*expr-==#* *expr-!=#* *expr->#* *expr->=#*
*expr-<#* *expr-<=#* *expr-=~#* *expr-!~#*
*expr-==?* *expr-!=?* *expr->?* *expr->=?*
*expr-<?* *expr-<=?* *expr-=~?* *expr-!~?*
*expr-is* *expr-isnot* *expr-is#* *expr-isnot#*
*expr-is?* *expr-isnot?*
'ignorecase'次第 大小文字考慮 大小文字無視 ~
等しい == ==# ==?
等しくない != !=# !=?
より大きい > ># >?
より大きいか等しい >= >=# >=?
より小さい < <# <?
より小さいか等しい <= <=# <=?
正規表現マッチ =~ =~# =~?
正規表現非マッチ !~ !~# !~?
同一のインスタンス is is# is?
異なるインスタンス isnot isnot# isnot?
例:
"abc" ==# "Abc" 0と評価される
"abc" ==? "Abc" 1と評価される
"abc" == "Abc" 'ignorecase' が設定されていれば1と、でなければ0と評価
*E691* *E692*
リスト|List|はリストとだけ比較可能で、==系、!=系、is、isnotのみ利用できる。
これらはそれぞれのリストの値を再帰的に比較する。大文字小文字無視にすると要素を
比較するときに大文字小文字を無視する。
*E735* *E736*
辞書|Dictionary|は辞書とだけ比較可能で、==系、!=系、is、isnotのみ利用できる。
これらは辞書のキー/値を再帰的に比較する。大文字小文字無視にすると要素を
比較するときに大文字小文字を無視する。
*E694*
|Funcref|は|Funcref|とだけ比較可能で、"equal", "not equal", "is", "isnot" のみ
利用できる。大文字小文字は常に区別される。引数や辞書が(部分適用に)バインドされ
ているかどうかも重要である。辞書も同値(あるいは "is" の場合は同一)でなければな
らず、引数も同値(あるいは同一)でなければならない。
関数参照が同じ関数を指しているのかを、バインドされた辞書や引数を無視して比較し
たい場合は、|get()| を使用して関数名を取得すればよい: >
if get(Part1, 'name') == get(Part2, 'name')
" Part1 と Part2 は同じ関数を指している
リスト (|List|) や 辞書 (|Dictionary|) に対して "is" や "isnot" を使うと、それ
らの式が同じリストのインスタンスを参照しているか判定される。リストのコピーと元
のリストは異なると判定される。リスト以外に対して "is" は "equal" と同じで、
"isnot" は "not equal" と同じである。ただし "is"、"isnot" は型が異なると値が等
しくない点が "==" とは異なる。 >
echo 4 == '4'
1
echo 4 is '4'
0
echo 0 is []
0
"is#"/"isnot#" と "is?"/"isnot?" は大文字小文字を区別するかどうかが違う。
文字列と数値を比較した場合、文字列が数値に変換され、数値として比較される。これ
は以下のようになることを意味する: >
echo 0 == 'x'
1
なぜなら、'x' は数値のゼロに変換されるからである。しかし、 >
echo [0] == ['x']
0
リストや辞書の中ではこの変換は行われない。
文字列同士を比較した場合、strcmp()やstricmp()によって比較される。これは数値的
に(バイトの値で)比較されるのであって、必ずしも言語に基づく文字種の違いではな
い。
'#' を付けた演算子を使うか、省略形かつ 'ignorecase' が設定されていない場合、比
較はstrcmp()で行われる。大文字・小文字は区別される。
'?' を付けた演算子を使うか、省略形かつ 'ignorecase' が設定されている場合、比較
はstricmp()で行われる。大文字・小文字は区別されない。
'smartcase' は適用されない。
"=~" と "!~" 演算子は右側の引数を正規表現のパターンとして、左側の引数に対して
マッチを試みる。正規表現のパターンに関しては|pattern|を参照。このマッチは
'magic' が設定され 'cpoptions' が空であるように振舞い、実際の 'magic' や
'cpoptions' に何が設定されているには依存しない。これがスクリプトをポータブルに
してくれる。正規表現中のバックスラッシュが重複してしまうのを避けるには、シング
ルクォーテーションの文字列を使用する。詳細は|literal-string|を参照。
文字列は単一行として扱われるので、複数行のパターン(\nを含むもの)はマッチしな
い。しかしながらリテラルなヌル文字(NL)を、普通の文字として代用することはでき
る。例:
"foo\nbar" =~ "\n" 1として評価される
"foo\nbar" =~ "\\n" 0として評価される
expr5 and expr6 *expr5* *expr6*
---------------
expr6 + expr6 .. 足し算、またはリストの連結 *expr-+*
expr6 - expr6 .. 引き算 *expr--*
expr6 . expr6 .. 文字列の連結 *expr-.*
リストに対しては "+" のみ可能で、expr6は両方ともリストでなければならない。結果
は2つのリストを連結した新しいリスト。
expr7 * expr7 .. 掛け算 *expr-star*
expr7 / expr7 .. 割り算 *expr-/*
expr7 % expr7 .. 剰余(割った余り) *expr-%*
"." を除く全ての演算子は自動的に文字列を数値に変換する。
ビット演算については |and()|, |or()|, |xor()| を参照。
"+" と "." の違いに注意:
"123" + "456" = 579
"123" . "456" = "123456"
'.' は '+' と '-' と等しい優先順位を持つので、次の式は: >
1 . 90 + 90.0
次のように解釈される: >
(1 . 90) + 90.0
これはエラーにならない。というのは、"190" は自動的に数値 190 に変換さ
れ、それと浮動小数点数 90.0 との和になる。しかし次の式は: >
1 . 90 * 90.0
次のように解釈される: >
1 . (90 * 90.0)
'.' は '*' より優先順位が低いためである。これはエラーになる。というのは、浮動
小数点数と文字列を結合することになるからである。
数値をゼロで割った結果は、被除数によって次のようになる:
0 / 0 = -0x80000000 (浮動小数点数の NaN のようなもの)
>0 / 0 = 0x7fffffff (正の無限大のようなもの)
<0 / 0 = -0x7fffffff (負の無限大のようなもの)
{訳注: >0 は正の数、<0 は負の数の意味}
(Vim 7.2 以前では常に 0x7fffffff だった)
64ビット数値が有効化されている場合は:
0 / 0 = -0x8000000000000000 (浮動小数点数の NaN のようなもの)
>0 / 0 = 0x7fffffffffffffff (正の無限大のようなもの)
<0 / 0 = -0x7fffffffffffffff (負の無限大のようなもの)
'%' の右辺(法)が0の場合、結果は0になる。
これらは全て|Funcref|には適用できない。
. と % は浮動小数点数には適用できない。 *E804*
expr7 *expr7*
-----
! expr7 論理否定 *expr-!*
- expr7 単項マイナス *expr-unary--*
+ expr7 単項プラス *expr-unary-+*
'!' 演算子では|TRUE|は|FALSE|に、|FALSE|は|TRUE|になる。
'-' では数値の符号が反転される。
'+" では変化はない。
文字列はまず数値に変換される。
これら2つは繰り返したり混ぜたりできる。例:
!-1 == 0
!!8 == 1
--9 == 9
expr8 *expr8*
-----
expr8[expr1] 文字列またはリストの要素 *expr-[]* *E111*
*E909* *subscript*
expr8が数値か文字列ならば、この値は文字列 expr8 の第 expr1 番目のバイトからな
る 1 バイトの文字列となる。expr8は文字列、expr1は数として扱われる。ただし
expr8 がマルチバイト文字列である場合、この値は単なるバイトコードであり、1文字
とはならないかもしれないことに注意。マルチバイト文字列に対する代替方法は
`byteidx()` を参照するか、`split()`を使って文字列を文字のリストに変換すれば良
い。
インデックスが0の場合、先頭のバイトが得られることに注意。これはC言語のように働
く。注意:カラム番号は1から始まる。例えばカーソルの下のバイトを得るためには、次
のようにする必要がある: >
:let c = getline(".")[col(".") - 1]
文字列の長さよりも大きなインデックスが指定された場合、結果は空文字列になる。負
数のインデックスを指定すると、結果は常に空文字列になる(後方互換性のため)。
最後のバイトを得るには[-1:]を使うこと。
expr8がリスト|List|ならばインデックスexpr1の要素が返る。取りうるインデックスの
値については|list-index|を参照。インデックスが範囲を超えている場合はエラーとな
る。例: >
:let item = mylist[-1] " 最後の要素を取得
一般的には、インデックスが正でリストの長さ以上または、負でリストの長さ×-1より
小さいときエラーとなる。
expr8[expr1a : expr1b] 部分文字列または部分リスト *expr-[:]*
expr8が数値か文字列ならば、expr1aバイトからexpr1bバイトまでの部分文字列となる
(両端を含む)。expr8は文字列として扱われ、expr1aとexpr1bは数値として扱われる。
Note マルチバイトのエンコーディングは認識しない。マルチバイト文字列のイン
デックスを計算する方法については |byteidx()| を参照。
expr1aが省略されたときは0となる。expr1bが省略されたときは文字列の長さ-1となる。
負数のインデックスを使うことによって文字列の末尾から取り出すことができる。-1は
最後の文字、-2は最後から2文字目…を表す。
インデックスがその文字の範囲外に出てしまったときは、その文字は省かれる。expr1b
がexpr1aより小さいときは空文字列となる。
例: >
:let c = name[-1:] " 文字列の最後のバイト
:let c = name[-2:-2] " 文字列の最後から2バイト目
:let s = line(".")[4:] " 5バイト目から末尾まで
:let s = s[:-3] " 最後の2文字を削除する
<
*slice*
expr8がリストならば、インデックスexpr1aとexpr1bの間の要素からなる新しいリスト
となる。すぐ上で説明した文字列の場合と同様である。部分リスト|sublist|も参照の
こと。例: >
:let l = mylist[:3] " 最初の4個の要素
:let l = mylist[4:4] " 1個の要素からなるリスト
:let l = mylist[:] " リストの浅いコピー
|Funcref|に対してexpr8[expr1]やexpr8[expr1a : expr1b]を使うとエラーになる。
部分リストでスコープと変数に続くコロンとの混乱に注意してください: >
mylist[n:] " 変数nは使える
mylist[s:] " スコープs:を使うとエラー!
expr8.name 辞書|Dictionary|の要素 *expr-entry*
expr8が辞書|Dictionary|のとき、ドットをつけるとその後に書かれた名前が辞書の
キーと見なされる。例: expr8[name]。
名前は変数名と同じようにアルファベットと数字だけから構成されなければならない
が、数字で始まってもよい。波括弧は使えない。
ドットの前後に空白があってはならない。
例: >
:let dict = {"one": 1, 2: "two"}
:echo dict.one