forked from ma6174/vim
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patheval.cnx
executable file
·7231 lines (6162 loc) · 291 KB
/
eval.cnx
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 version 7.3. 最近更新: 2010年8月
VIM 参考手册 by Bram Moolenaar
译者: Willis
http://vimcdoc.sf.net
表达式求值 *expression* *expr* *E15* *eval*
用户手册第 41 章 |usr_41.txt| 有使用表达式的介绍。
注意: 表达式求值可以在编译时关闭。如果你这么做,本文档介绍的特性就不复存在。见
|+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. 沙盘 (sandbox) |eval-sandbox|
12. 文本锁 |textlock|
{Vi 无此功能}
==============================================================================
1. 变量 *variables*
1.1 变量类型 ~
*E712*
有六种类型的变量:
数值 32 位带符号整数。|expr-number| *Number*
示例: -123 0x10 0177
浮点数 带小数的数值。|floating-point-format| *Float*
{仅当编译时加入 |+float| 特性才有效}
示例: 123.456 1.15e-6 -1.1e3
字符串 NUL 结尾的 8 位无符号字符 (即字节) 的串。|expr-string|
示例: "ab\txx\"--" 'x-z''a,c'
函数引用 指向一个函数的引用 |Funcref|。
示例: function("strlen")
列表 项目的有序的序列 |List|。
示例: [1, 2, ['a', 'b']]
字典 关联的无序数组: 每个项目包含一个键和一个值。|Dictionary|
示例: {'blue': "#0000ff", 'red': "#ff0000"}
数值和字符串类型之间会根据使用的情况自动转换。
数值到字符串的转换使用数值的 ASCII 表示。例如: >
数值 123 --> 字符串 "123"
数值 0 --> 字符串 "0"
数值 -1 --> 字符串 "-1"
*octal*
字符串到数值的转换则把字符串开头的一系列数字位转换成数值。十六进制 "0xf9" 和八
进制 "017" 形式的数值可以识别。如果字符串不以数字开始,则结果为零。例如: >
字符串 "456" --> 数值 456
字符串 "6bar" --> 数值 6
字符串 "foo" --> 数值 0
字符串 "0xf1" --> 数值 241
字符串 "0100" --> 数值 64
字符串 "-8" --> 数值 -8
字符串 "+8" --> 数值 0
要强制从字符串转换到数值,给它加零: >
:echo "0100" + 0
< 64 ~
要避免开头的零导致八进制的转换,或者想换不同的基底,用 |str2nr()|。
布尔型的操作使用数值类型。零代表假值 (FALSE),非零代表真值 (TRUE)。
注意 在命令 >
:if "foo"
里,"foo" 被转换成 0,也就是假值。要测试字符串非空,应该使用 strlen(): >
:if strlen("foo")
< *E745* *E728* *E703* *E729* *E730* *E731*
列表、字典和函数引用类型不会自动进行转换。
*E805* *E806* *E808*
混合数值和浮点数的计算时,数值转换为浮点数。否则没有自动到浮点数的转换。用
str2float() 可转换字符串到浮点数,printf() 从浮点数到字符串,float2nr() 则从浮
点数到数值。
*E706* *sticky-type-checking*
如果你试图改变变量类型,你会得到错误。先 |:unlet| 可以避免此错误。不过,字符串
和数值被认为是等价的类型,浮点数和数值之间也是如此。考虑如下的命令序列: >
:let l = "string"
:let l = 44 " 类型从字符串改为数值
:let l = [1, 2, 3] " 出错!l 仍为数值
:let l = 4.4 " 类型从数值改为浮点数
:let l = "string" " 出错!
1.2 函数引用 ~
*Funcref* *E695* *E718*
函数引用变量可以通过 |function()| 函数得到。可以在表达式里用它来代替函数名,在
围绕参数的括号之前,以调用它引用的函数。例如: >
:let Fn = function("MyFunc")
:echo Fn()
< *E704* *E705* *E707*
函数引用变量必须以大写字母、"s:"、"w:"、"t:" 或 "b:" 开始。函数引用变量不能和
任何函数重名。
特例是可以定义函数并直接把它的函数引用赋给字典的一个项目。例如: >
: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)
1.3 列表 ~
*List* *Lists* *E686*
列表是项目的有序序列。项目可以是任何类型,用索引号可以进行访问。可以在序列的任
何位置上增加或者删除项目。
列表建立 ~
*E696* *E697*
列表用方括号里逗号分隔的项目序列建立。例如: >
:let mylist = [1, two, 3, "four"]
:let emptylist = []
项目可以是任何表达式。用列表作为项目就能建立列表的列表: >
:let nestlist = [[11, 12], [21, 22], [31, 32]]
忽略末项之后额外的逗号。
列表索引 ~
*list-index* *E684*
在列表之后的方括号中放上索引号可以访问列表项目。索引从零开始,也就是说,第一个
项目的索引值为零。 >
:let item = mylist[0] " 得到第一个项目: 1
:let item = mylist[2] " 得到第三个项目: 3
如果返回的项目本身是列表,可以重复这样的操作: >
:let item = nestlist[0][1] " 得到第一个列表的第二个项目: 12
<
负索引从尾端开始计算。索引 -1 指向列表的最后一个项目,-2 指向倒数第二个项目,
依此类推。 >
:let last = mylist[-1] " 得到最后一个项目: "four"
要避免非法索引值产生的错误,用 |get()| 函数。如果项目不存在,它返回零或者你指
定的缺省值: >
:echo get(mylist, idx)
:echo get(mylist, idx, "NONE")
列表连接 ~
两个列表可以用 "+" 操作符连接: >
:let longlist = mylist + [5, 6]
:let mylist += [7, 8]
要在前面或后面附加项目,在项目外面加上 [] 从而把它变为一个列表。要改变列表内部
的值,见下 |list-modification|。
子列表~
列表的一部分可以通过指定首末两个索引获得,方括号内以冒号分隔两者: >
:let shortlist = mylist[2:-1] " 得到列表 [3, "four"]
首索引的省略类似于用 0。末索引的省略类似于用 -1。 >
:let endlist = mylist[2:] " 从项目 2 到结束: [3, "four"]
:let shortlist = mylist[2:2] " 单个项目的列表: [3]
:let otherlist = mylist[:] " 复制列表
如果首索引在列表末项之后或者末索引小于首索引,返回空列表。没有错误信息。
如果末索引大于等于列表的长度,使用列表长度减一: >
:let mylist = [0, 1, 2, 3]
:echo mylist[2:8] " 返回: [2, 3]
<
注意: mylist[s:e] 意味着用变量 "s:e" 作为索引。在 ":" 之前用单个字母作为变量要
小心。需要的话加上空格: 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 层。
可用操作符 "is" 检查两个变量是否指向同一个列表。"isnot" 刚好相反。与此对照,
"==" 比较两个列表的值是否相同。 >
:let alist = [1, 2, 3]
:let blist = [1, 2, 3]
:echo alist is blist
< 0 >
:echo alist == blist
< 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:]
如果只有两个项目,不会报错。这时 "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) " 在 list[3] 前插入项目 'a'
:call add(list, "new") " 在最后附加字符串项目
:call add(list, [1, 2]) " 在最后附加新的列表项目
:call extend(list, [1, 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) " 反转项目的顺序
For 循环 ~
|:for| 循环为每个列表项目执行命令。一个变量被依次设为每个列表项目。例如: >
: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
注意 所有列表项目必须是相同类型,不然会报错 |E706|。要避免这一点,在循环尾部
|:unlet| 该变量。
如果你只是想要修改每个列表项目,|map()| 函数比 for 循环简单得多。
就像 |:let| 命令,|:for| 也可以接受变量的列表。这需要参数是列表的列表。 >
:for [lnum, col] in [[1, 3], [2, 8], [3, 0]]
: call Doit(lnum, col)
:endfor
这就像对列表的每个项目使用了 |:let| 命令。重复一次,类型必须相同,否则会报错。
也可以用变量保存列表变量的其余项目: >
: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) " 检查 list 是否为空
:let l = len(list) " list 项目的数量
:let big = max(list) " list 项目的最大值
:let small = min(list) " list 项目的最小值
:let xs = count(list, 'x') " 计算 list 里 'x' 出现的次数
:let i = index(list, 'x') " list 第一个 'x' 的位置
:let lines = getline(1, 10) " 得到缓冲区十行文本行
:call append('$', lines) " 附加若干文本行到缓冲区尾部
:let list = split("a b c") " 用字符串中的项目建立列表
:let string = join(list, ', ') " 用 list 项目构造字符串
:let s = string(list) " list 的字符串表示
:call map(list, '">> " . v:val') " 在每个项目前加上 ">> "
不要忘记组合使用不同功能可以简化任务。例如,要计算列表中所有数值的总和: >
:exe 'let sum = ' . join(nrlist, '+')
1.4 字典 ~
*Dictionaries* *Dictionary*
字典是关联数组: 每个项目有一个键和一个值。用键可以定位项目,而项目的存储不能确
定任何特定顺序。
字典建立 ~
*E720* *E721* *E722* *E723*
字典通过花括号里逗号分隔的项目列表建立。每个项目包含以冒号分隔的键和值。一个键
只能出现一次。例如: >
:let mydict = {1: 'one', 2: 'two', 3: 'three'}
:let emptydict = {}
< *E713* *E716* *E717*
键必须是字符串。用数值也可以,但它总被自动转换为字符串。所以字符串 '4' 和数值
4 总会找到相同的项目。注意 字符串 '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
键列表没有经过排序。你可能希望先进行排序: >
:for key in sort(keys(mydict))
要遍历所有的值,用 |values()| 函数: >
:for v in values(mydict)
: echo "value: " . v
:endfor
如果你想同时得到键和值,用 |items()| 函数。它返回一个列表,其中每个项目是两个
项目的列表: 键和值: >
: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
如果所有的键-值组对的比较结果相同,两个字典比较的结果也相同。详情见
|list-identity|。
字典修改 ~
*dict-modification*
要修改字典已经存在的项目或者增加新的项目,用 |:let|: >
:let dict[4] = "four"
:let dict['one'] = item
从字典里删除项目可以通过 |remove()| 或 |:unlet| 完成。
从 dict 里删除键 "aaa" 的项目有三种方法: >
:let i = remove(dict, 'aaa')
:unlet dict.aaa
:unlet dict['aaa']
两个字典的合并可以用 |extend()|: >
:call extend(adict, bdict)
这使得 adict 得到扩展,加入所有的 bdict 项目。对于重复的键,adict 项目被覆盖。
可选的第三个参数可以改变这一点。
注意 这不影响字典项目的顺序,不要希望 ":echo adict" 会先显示原有 adict 项目,
然后再显示 bdict 的项目。
从字典里删除多个项目可以用 |filter()| 完成: >
:call filter(dict, 'v:val =~ "x"')
删除 "dict" 里所有值不匹配 "x" 的项目。
字典函数 ~
*Dictionary-function* *self* *E725*
定义函数时,如果带有 "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" 属性的函数的函数引用,不过这时无法使用 "self"
变量。
*numbered-function* *anonymous-function*
要避免额外的函数名,可以定义时直接赋给字典: >
:let mydict = {'data': [0, 1, 2, 3]}
:function mydict.len() dict
: return len(self.data)
:endfunction
:echo mydict.len()
该函数会得到一个编号,而 dict.len 的值是指向此函数的 |Funcref|。该函数只能通过
|Funcref| 访问。如果没有任何 |Funcref| 引用,它会被自动删除。
编号函数不一定要有 "dict" 属性。
如果你的编号函数有错,可以用一个技巧知道它是什么内容。假定函数是 42,命令为: >
:function {42}
字典相关函数 ~
*E715*
可以用于字典的函数: >
:if has_key(dict, 'foo') " 如果 dict 有带 "foo" 键的项目则为真
:if empty(dict) " 如果 dict 为空则为真
:let l = len(dict) " dict 项目的数量
:let big = max(dict) " dict 项目的最大值
:let small = min(dict) " dict 项目的最小值
:let xs = count(dict, 'x') " 统计 dict 里 'x' 出现的数目
:let s = string(dict) " dict 的字符串表示
:call map(dict, '">> " . v:val') " 在每个项目前加上 ">> "
1.5 变量的更多细节 ~
*more-variables*
如果你需要知道变量或表达式的类型,使用 |type()| 函数。
如果 'viminfo' 选项包含 '!' 标志位,大写开头且不包含小写字母的全局变量被保存在
viminfo 文件里 |viminfo-file|。
如果 'sessionoptions' 选项包含 "global",大写开头且包含至少一个小写字母的全局
变量被保存在会话文件里 |session-file|。
变量名 可以保存的位置 ~
my_var_6 无
My_Var_6 会话文件
MY_VAR_6 viminfo 文件
可以使用花括号来构造变量名,见 |curly-braces-names|。
==============================================================================
2. 表达式语法 *expression-syntax*
表达式语法小结,优先级从低到高排列:
|expr1| expr2 ? expr1 : expr1 if-then-else
|expr2| expr3 || expr3 .. 逻辑或
|expr3| expr4 && expr4 .. 逻辑与
|expr4| expr5 == expr5 等于
expr5 != expr5 不等于
expr5 > expr5 大于
expr5 >= expr5 大于等于
expr5 < expr5 小于
expr5 <= expr5 小于等于
expr5 =~ expr5 匹配正规表达式
expr5 !~ expr5 不匹配正规表达式
expr5 ==? expr5 等于,忽略大小写
expr5 ==# expr5 等于,匹配大小写
等等 如上,? 忽略大小写,# 则匹配之
expr5 is expr5 相同的 |List| 实例
expr5 isnot expr5 不同的 |List| 实例
|expr5| expr6 + expr6 .. 数值加法或列表连接
expr6 - expr6 .. 数值减法
expr6 . expr6 .. 字符串连接
|expr6| expr7 * expr7 .. 数值乘法
expr7 / expr7 .. 数值除法
expr7 % expr7 .. 数值求余
|expr7| ! expr7 逻辑非
- expr7 一元减法: 取反
+ expr7 一元加法: 原值
|expr8| expr8[expr1] 字符串里的字节或者 |List| 的项目
expr8[expr1 : expr1] 字符串子串或 |List| 的子列表
expr8.name |Dictionary| 的项目
expr8(expr1, ...) 使用 |Funcref| 变量的函数调用
|expr9| number 数值常数
"string" 字符串常数,反斜杠有特殊含义
'string' 字符串常数,' 加倍
[expr1, ...] |List|
{expr1: expr1, ...} |Dictionary|
&option 选项值
(expr1) 嵌套表达式
variable 内部变量
va{ria}ble 带花括号的内部变量
$VAR 环境变量
@r 寄存器 'r' 的值
function(expr1, ...) 函数调用
func{ti}on(expr1, ...) 带花括号的函数调用
".." 标明这一层上的操作可以连接。比如: >
&nu || &list && &shell == "csh"
同一层的表达式从左到右进行分析。
expr1 *expr1* *E109*
-----
expr2 ? expr1 : expr1
'?' 之前的表达式作为数值求值。如果结果非零,最终的结果是 '?' 和 ':' 之间的表达
式的值,不然最终的结果是 ':' 之后的表达式的值。例如: >
:echo lnum == 1 ? "top" : lnum
因为第一个表达式是 "expr2",它不能包含另一个 ?:。另外两个表达式则没有这个限
制,从而使得递归使用 ?: 成为可能。例如: >
:echo lnum == 1 ? "top" : lnum == 1000 ? "last" : lnum
要使之可读,建议使用续行符 |line-continuation|: >
:echo lnum == 1
:\ ? "top"
:\ : lnum == 1000
:\ ? "last"
:\ : lnum
在 ':' 前,你总是应该加上空格,否则它可能被错误用在如 "a:1" 这样的变量里。
expr2 和 expr3 *expr2* *expr3*
---------------
*expr-barbar* *expr-&&*
"||" 和 "&&" 操作符左右两边各接受一个参数。参数是 (或转化为) 数值。运算结果是:
输入 输出 ~
n1 n2 n1 || n2 n1 && n2 ~
零 零 零 零
零 非零 非零 零
非零 零 非零 零
非零 非零 非零 非零
操作符可以连接。比如: >
&nu || &list && &shell == "csh"
注意 "&&" 比 "||" 优先级高,所以这等价于: >
&nu || (&list && &shell == "csh")
一旦结果可以确定,表达式使用 "短路" 计算,也就是,不再计算后面的参数,这和 C
的情形类似。比如: >
let a = 1
echo a || b
这是合法的,即使没有叫 "b" 的变量也是如此。因为 "a" 已经是非零值,结果必然是非
零。下面的情形类似: >
echo exists("b") && b == "yes"
无论 "b" 定义与否,这是合法的。第二个子句只有在 "b" 定义的时候才会被计算。
expr4 *expr4*
-----
expr5 {cmp} expr5
比较两个 expr 表达式,如果结果为假,返回 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*
使用 'ignorecase' 匹配大小写 忽略大小写 ~
等于 == ==# ==?
不等于 != !=# !=?
大于 > ># >?
大于等于 >= >=# >=?
小于 < <# <?
小于等于 <= <=# <=?
匹配正规表达式 =~ =~# =~?
不匹配正规表达式 !~ !~# !~?
相同实例 is
不同实例 isnot
示例:
"abc" ==# "Abc" 结果为 0
"abc" ==? "Abc" 结果为 1
"abc" == "Abc" 如果置位了 'ignorecase',结果为 1,不然结果为 0
*E691* *E692*
|List| 只能和 |List| 比较,而且只能用 "等于"、"不等于" 和 "is"。比较针对列表的
值,递归进行。忽略大小写意味着比较项目的值时忽略大小写。
*E735* *E736*
|Dictionary| 只能和 |Dictionary| 比较,而且只能用 "等于"、"不等于" 和 "is"。比
较针对 |Dictionary| 的键/值,递归进行。忽略大小写意味着比较项目的值时忽略大小
写。
*E693* *E694*
|Funcref| 只能和 |Funcref| 比较,而且只能用 "等于" 和 "不等于"。这里永不忽略大
小写。
|List| 用 "is" 或 "isnot" 时,检查表达式是否指向同一个 |List| 实例。|List| 的
备份和原来的 |List| 不同。如果不是 |List|,用 "is" 等价于用 "等于",而 "isnot"
等价于 "不等于",有一点区别: 不同的类型总认为有不同的值。"4 == '4'" 为真,而
"4 is '4'" 为假。
如果比较字符串和数值,字符串被转化成数值,而比较是在数值之间进行的。这意味着
"0 == 'x'" 为真,因为 'x' 被转化成数值 0。
如果比较两个字符串,使用 strcmp() 或 stricmp()。因而,比较的是数学上的差异 (比
较字节码),而不必然是本地语言的字母的差异。
如果操作符后带上 '#',或者 'ignorecase' 关闭时使用无 '#' 的版本时,比较使用
strcmp(): 大小写相关。
如果操作符后带上 '?',或者 'ignorecase' 打开时使用无 '?' 的版本时,比较使用
stricmp(): 大小写无关。
这里 'smartcase' 不适用。
"=~" 和 "!~" 操作符使用右边的参数作为模式来匹配左边的参数。模式的定义见
|pattern|。匹配进行时,总是假设置位了 'magic' 并且 'cpoptions' 为空,无论
'magic' 或 'cpoptions' 实际的值为何。这使得脚本可移植。要避免在正规表达式里使
用的反斜杠需要加倍的问题,可以使用单引号的字符串,见 |literal-string|。
既然字符串假定为单行,多行的模式 (包含 \n,即反斜杠-n) 不会被匹配。不过,按本
义出现的单个 NL 字符可以像普通字符一样匹配。比如:
"foo\nbar" =~ "\n" 结果为 1
"foo\nbar" =~ "\\n" 结果为 0
expr5 和 expr6 *expr5* *expr6*
---------------
expr6 + expr6 .. 数值加法或 |List| 连接 *expr-+*
expr6 - expr6 .. 数值减法 *expr--*
expr6 . expr6 .. 字符串连接 *expr-.*
|Lists| 只能用 "+",而且两个 expr6 必须都是列表。返回两者连接以后的新列表。
expr7 * expr7 .. 数值乘法 *expr-star*
expr7 / expr7 .. 数值除法 *expr-/*
expr7 % expr7 .. 数值求余 *expr-%*
除了 "." 以外,这里所有的操作都把字符串转化成数值。
注意 "+" 和 "." 的差异:
"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 (类似于负无穷大)
(Vim 7.2 之前,总是返回 0x7fffffff)
如果 '%' 的右边为零,结果为 0。
这些操作不适用于 |Funcref|。
而 % 也不适用于浮点数。 *E804*
expr7 *expr7*
-----
! expr7 逻辑非 *expr-!*
- expr7 一元减法: 取反 *expr-unary--*
+ expr7 一元加法: 原值 *expr-unary-+*
'!' 把非零变为零,零变为 1。
'-' 改变数值的符号。
'+' 保持原值。
字符串会先转化为数值。
可以重复和混合这三种运算。例如:
!-1 == 0
!!8 == 1
--9 == 9
expr8 *expr8*
-----
expr8[expr1] 字符串或 |List| 的项目 *expr-[]* *E111*
如果 expr8 是数值或字符串,结果是字符串,包含 expr8 里第 expr1 个字节。expr8
视作字符串,expr1 视作数值。这里不识别多字节编码,但可考虑使用 |byteidx()|。
索引 0 给出第一个字符。这和 C 类同。要小心: 文本列号可是从 1 开始的!例如,要
得到光标所在的字符: >
:let c = getline(line("."))[col(".") - 1]
如果字符串的长度小于索引值,结果为空字符串。负索引总是给出空字符串 (原因: 反向
兼容)。用 [-1:] 得到最后一个字节。
如果 expr8 是 |List|,返回索引值为 expr1 的项目。可用的索引值见 |list-index|。
如果索引越界,产生错误。例如: >
:let item = mylist[-1] " 得到最后一个项目
一般的,如果 |List| 索引大于等于 |List| 的长度,或者比 |List| 的长度更负,产生
错误。
expr8[expr1a : expr1b] 子字符串或子列表 *expr-[:]*
如果 expr8 是数值或字符串,结果是子字符串,包含第 expr1a 到第 expr1b (包含) 个
字节。expr8 视作字符串,expr1a 和 expr1b 视作数值。这里不识别多字节编码,需用
|byteidx()| 来计算索引值。
如果省略 expr1a,用零。如果省略 expr1b,用字符串的长度减一。
可以用负数来从字符串尾部开始计算位置。-1 代表最后一个字符,-2 倒数第二个,依此
类推。
如果索引越界,忽略这些字符。如果 expr1b 小于 expr1a,结果是空字符串。
例如: >
:let c = name[-1:] " 字符串最后一个字节
:let c = name[-2:-2] " 字符串倒数第二个字节
:let s = line(".")[4:] " 从第五个字节到最后
:let s = s[:-3] " 删除最后两个字节
<
*sublist* *slice*
如果 expr8 是 |List|,结果是新的 |List|,包含 expr1 和 expr1b 索引指定的项目。
和上面描述的字符串情形类似,除了越界的索引会报错以外。例如: >
:let l = mylist[:3] " 前四个项目
:let l = mylist[4:4] " 单个项目的列表
:let l = mylist[:] " 列表的浅备份
在 |Funcref| 上用 expr8[expr1] 或 expr8[expr1a : expr1b] 出错。
expr8.name |Dictionary| 的项目 *expr-entry*
如果 expr8 是一个 |Dictionary| 且后跟句号再跟一个名字,该名字用作 |Dictionary|
的键。这相当于: expr8[name]。
该名字必须由字母数字字符组成。这和变量名一样,不过这里可以用数字开始。但不能用
花括号。
句号前后不能用空白。
例如: >
:let dict = {"one": 1, 2: "two"}
:echo dict.one
:echo dict .2
注意 句号也用于字符串连接。要避免混淆,用于字符串连接的句号前后加上空白。
expr8(expr1, ...) |Funcref| 函数调用
如果 expr8 是 |Funcref| 类型的变量,调用它指向的函数。
*expr9*
number
------
number 数值常数 *expr-number*
十进制、十六进制 (0x 或 0X 开始)、或八进制 (0 开始)。
*floating-point-format*
浮点数可用两种形式给出:
[-+]{N}.{M}
[-+]{N}.{M}e[-+]{exp}
{N} 和 {M} 都是数值。{N} 和 {M} 都必须存在,且只能包含数位。
[-+] 意味着有一个可选的正负号。
{exp} 是指数部分,以 10 为基。
只能接受小数点,逗号不行。这和当前的 locale 无关。
{仅当编译时加入 |+float| 特性才有效}
示例:
123.456
+0.0001
55.0
-0.123
1.234e03
1.0E-6
-3.1416e+88
下面的形式是_非法的_:
3. {M} 为空
1e40 {M} 为空
*float-pi* *float-e*
可以复制-粘贴的一些常用值: >
:let pi = 3.14159265359
:let e = 2.71828182846
逻辑:
浮点数引入之前,文本 "123.456" 被解释为两个数值 "123" 和 "456",转换为字符串,
然后进行连接而生成字符串 "123456"。这被认为没有意义,也没有找到有意使用此特性
的 Vim 脚本,因此我们采纳了这种普遍的浮点数记法,而接受其后向不兼容性。
*floating-point-precision*
浮点数的精度和取值范围取决于 Vim 编译时使用的库如何理解 "double"。运行时无法改
变。
浮点数 |Float| 的显示缺省使用 6 位十进制位,类似于 printf("%g", f)。使用
|printf()| 函数时可以指定其它位数。例如: >
:echo printf('%.15e', atan(1))
< 7.853981633974483e-01
string *expr-string* *E114*
------
"string" 字符串常数 *expr-quote*
注意 使用的是双引号。
字符串常数接受以下特殊字符:
\... 三位八进制数 (例如,"\316")
\.. 两位八进制数 (必须后跟非数字)
\. 一位八进制数 (必须后跟非数字)
\x.. 两位十六进制数指定的字节 (例如,"\x1f")
\x. 一位十六进制数指定的字节 (必须后跟非十六进制数字)
\X.. 等同于 \x..
\X. 等同于 \x.
\u.... 四位十六进制指定的字符。根据 'encoding' 的当前值决定的编码进行存贮 (例
如,"\u02a4")
\U.... 等同于 \u.....
\b 退格 <BS>
\e escape <Esc>
\f 换页 <FF>
\n 换行 <NL>
\r 回车 <CR>
\t 制表 <Tab>
\\ 反斜杠
\" 双引号
\<xxx> "xxx" 命名的特殊字符,例如 "\<C-W>" 代表 CTRL-W。用于映射,0x80 字节被
转义。不要用 <Char-xxxx> 来得到 utf-8 字符,用上面提到的 \uxxxxx。
注意 "\xff" 保存为字节 255,在某些编码中它是不合法的。使用 "\u00ff" 可以按照
'encoding' 的当前值保存字符 255。
注意 "\000" 和 "\x00" 强制字符串结束。
literal-string *literal-string* *E115*
---------------
'string' 字符串常数 *expr-'*
注意 使用的是单引号。
字符串这里按原义出现。不去掉反斜杠,它也没有特殊含义。唯一的特例是两个单引号代
表一个单引号。
单引号字符串有助于模式的使用,因为反斜杠不再需要加倍。以下两个命令等价: >
if a =~ "\\s*"
if a =~ '\s*'
option *expr-option* *E112* *E113*
------
&option 选项值,如有存在,使用局部值
&g:option 全局选项值
&l:option 局部选项值
例如: >
echo "tabstop is " . &tabstop
if &insertmode
这里可以使用任何选项值。见 |options|。如果指定要使用局部值,但不存在局部于缓冲
区或局部于窗口的选项,则还是使用全局值。
register *expr-register* *@r*
--------
@r 寄存器 'r' 的值
结果是命名寄存器的内容,以单个字符串表达。换行符在需要时会被插入。要得到无名寄
存器的内容,使用 @" 或 @@。可用寄存器的相关解释可见 |registers|。
如果用 '=' 寄存器,你得到表达式自身,而不是它计算的结果。用 |eval()| 来进行计
算。
nesting *expr-nesting* *E110*
-------
(expr1) 嵌套表达式
environment variable *expr-env*
--------------------
$VAR 环境变量
任何环境变量的字符串值。如果该环境变量没有定义,结果为空字符串。
*expr-env-expand*
注意 直接使用 $VAR 和使用 expand("$VAR") 有区别。直接使用的形式只能扩展当前
Vim 会话所知的环境变量。使用 expand() 会先尝试当前 Vim 会话所知的环境变量,如
果不成功,则使用外壳扩展该变量。这会变慢,但可以用来扩展只有外壳知道的变量。
例如: >
:echo $version
:echo expand("$version")