You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: ch12_search_and_substitute.md
+124-4Lines changed: 124 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -78,6 +78,36 @@ To match both "hello" and "hola", you can do `/hello\|hola`. You have to escape
78
78
79
79
If you don't want to type `\|` every time, you can use the `magic` syntax (`\v`) at the start of the search: `/\vhello|hola`. I will not cover `magic` in this chapter, but with `\v`, you don't have to escape special characters anymore. To learn more about `\v`, feel free to check out `:h \v`.
80
80
81
+
# Setting the Start and End of a Match
82
+
83
+
Maybe you need to search for a text that is a part of a compound word. If you have these texts:
84
+
85
+
```
86
+
11vim22
87
+
vim22
88
+
11vim
89
+
vim
90
+
```
91
+
92
+
If you need to select "vim" but only when it starts with "11" and ends with "22", you can use `\zs` (starting match) and `\ze` (ending match) operators. Run:
93
+
94
+
```
95
+
/11\zsvim\ze22
96
+
```
97
+
98
+
Vim still has to match the entire pattern "11vim22", but only highlights the pattern sandwiched between `\zs` and `\ze`. Another example:
99
+
100
+
```
101
+
foobar
102
+
foobaz
103
+
```
104
+
105
+
If you need to search for the "foo" in "foobaz" but not in "foobar", run:
106
+
107
+
```
108
+
/foo\zebaz
109
+
```
110
+
81
111
# Searching Character Ranges
82
112
83
113
All your search terms up to this point have been a literal word search. In real life, you may have to use a general pattern to find your text. The most basic pattern is the character range, `[ ]`.
@@ -232,7 +262,7 @@ In Vim, `%` usually means the entire file. If you run `:%s/let/const/`, it will
232
262
233
263
# Pattern Matching
234
264
235
-
The next few sections will cover basic regular expressions. A strong pattern knowledge is essential to master the substitute command.
265
+
The next few sections will cover basic regular expressions. A strong pattern knowledge is essential to master the substitute command.
236
266
237
267
If you have the following expressions:
238
268
@@ -495,16 +525,106 @@ Here is the breakdown:
495
525
-`\1` is the first match group, which is either the text "hello" or "hola".
496
526
-`friend` is the literal word "friend".
497
527
528
+
# Substituting the Start and the End of a Pattern
529
+
530
+
Recall that you can use `\zs` and `\ze` to define the start and the end of a match. This technique works in substitution too. If you have:
531
+
532
+
```
533
+
chocolate pancake
534
+
strawberry sweetcake
535
+
blueberry hotcake
536
+
```
537
+
538
+
To substitute the "cake" in "hotcake" with "dog" to get a "hotdog":
539
+
540
+
```
541
+
:%s/hot\zscake/dog/g
542
+
```
543
+
544
+
Result:
545
+
546
+
```
547
+
chocolate pancake
548
+
strawberry sweetcake
549
+
blueberry hotdog
550
+
```
551
+
552
+
You can also substitute the nth match in a line with this trick:
553
+
554
+
```
555
+
One Mississippi, two Mississippi, three Mississippi, four Mississippi, five Mississippi.
556
+
```
557
+
558
+
To substitute the third "Mississippi" with "Arkansas", run:
559
+
560
+
```
561
+
:s/\v(.{-}\zsMississippi){3}/Arkansas/g
562
+
```
563
+
564
+
The breakdown:
565
+
-`:s/` the substitute command.
566
+
-`\v` is the magic keyword so you don't have to escape special keywords.
567
+
-`.` matches any single character
568
+
-`{-}` performs non-greedy match of 0 or more of the preceding atom.
569
+
-`\zsMississippi` makes "Mississippi" the start of the match.
570
+
-`(...){3}` looks for the third match.
571
+
572
+
You have seen the `{3}` syntax before. It is a type of `{n,m}`. In this case, you have `{3}` which will match exactly the third match. The new trick here is `{-}`. It is a non-greedy match. It finds the shortest match of the given pattern. In this case, `(.{-}Mississippi)` matches the least amount of "Mississippi" preceded by any character. Contrast this with `(.*Mississippi)` where it finds the longest match of the given pattern.
573
+
574
+
If you use `(.{-}Mississippi)`, you get five matches: "One Mississippi", "Two Mississippi", etc. If you use `(.*Mississippi)`, you get one match: the last "Mississippi". To learn more check out `:h /\{-` and `:h non-greedy`.
575
+
576
+
Let's do a simpler example. If you have the string:
577
+
578
+
```
579
+
abc1de1
580
+
```
581
+
582
+
You can match "abc1de1" (greedy) with:
583
+
584
+
```
585
+
/a.*1
586
+
```
587
+
588
+
You can match "abc1" (non-greedy) with:
589
+
590
+
```
591
+
/a.\{-}1
592
+
```
593
+
594
+
So if you need to uppercase the longest match (greedy), run:
595
+
596
+
```
597
+
:s/a.*1/\U&/g
598
+
```
599
+
600
+
To get:
601
+
602
+
```
603
+
ABC1DEFG1
604
+
```
605
+
606
+
If you need to uppercase the shortest match (non-greedy), run:
607
+
608
+
```
609
+
:s/a.\{-}1/\U&/g
610
+
```
611
+
612
+
To get:
613
+
614
+
```
615
+
ABC1defg1
616
+
```
617
+
498
618
# Substituting Across Multiple Files
499
619
500
620
Finally, let's learn how to substitute phrases across multiple files. For this section, assume that you have two files: `food.txt` and `animal.txt`.
0 commit comments