3

I have the text pattern [2] in a text file. I want to replace it with the text string [1].

Using this command:

:%s/\<[2]\>/[1]/

Vim only replaces the string '2' in the square brackets so the result is [[1]].

I read that when searching:

After an opening [, everything until the next closing ] specifies a /collection source.

So I tried escaping the square brackets:

:%s/\<\[2\]\>/[1]/

But I received this error:

E486: Pattern not found: \<\[2\]\>

Enclosing the entire pattern in the brackets (:%s/\<[[2]]\>/[1]/) also returns the E486: Pattern not found: \<[[2]]\> error

Then removing the special character (or more accurately escape sequence) for the beginning of a word ('<') and the end of a word ('>') i.e. :%s/[[2]]/[1]/ gives the result [[1].

  1. When searching with the :s (substitute) command, the collection [[2]] should match any single character '[', '2' or ']', so why does :%s/\<[[2]]\>/[1]/ cause an E486: Pattern not found: \<[[2]]\> error?
  2. How do you search for text patterns consisting of an opening bracket ([) and closing bracket (]) e.g. the text pattern [2]?
  3. Why is [ ] interpreted as a collection in the search part of the substitute command, but [ ] is not interpreted as a collection in the replace part of the substitute command?
  4. Why does :%s/[[2]]/[1]/ only replace the text pattern '2]' i.e. giving the result [[1]?
  5. Does enclosing the entire pattern in the brackets (:%s/\<[[2]]\>/[1]/) return an E486: Pattern not found: \<[[2]]\> error because Vim tries looking for the text pattern '[[2]]' but couldn't find it, or is something else causing this error?
  6. The command :%s/\<[2]\>/[1]/ only replaces the string 2 in the square brackets (the result is [[1]]), which indicates that the collection [2] matches only the single character 2, but what happened to the beginning-of-a-word escape sequence ('<') and the ending-of-a-word escape sequence ('>')? Why do the escape sequences have no effect or not cause an error?

1 Answer 1

4

Before we get to all the questions, the way I'd achieve what you're looking to do is with the following:

:%s/\[2\]/[1]

or the following if you just want to change the text inside the [] without having to specify them again in the replacement part:

:%s/\[\zs2\ze\]/1

I believe the reason you are getting the "Pattern not found" error when you escape the square brackets is because \< is expecting the next character to be a "word character", but square brackets aren't considered to be a word character by default, so it gets a bit confused.

When you remove the \< and \> and search for [[2]], I think vim is trying to be clever about the way it interprets the brackets. The first [ starts the collection and the first ] closes the collection and inside the collection it's trying to match either a literal [ or a 2. Then the second ] is being being interpreted as a literal ] since it would otherwise be a syntax error since there is no opening [ to match it. So, it's basically looking for either a [ or a 2 that is immediately followed by a ]. It matches the 2] and replaces that with [1] so you end up with [[1].

Answers to your other questions:

  1. As I tried to explain above (probably confusingly), it's only looking for either a [ or a 2. The first ] is terminating the collection. Then the second ] is being interpreted as a literal ]. I think you may have a typo in the question: :%s/[[2]]/[1]/ should result in [[1] and not the "Pattern not found" error.
  2. You had the right idea with escaping the brackets with \. The problem was with the \< and \>. The pattern should be \[2\] to match [2].
  3. It wouldn't really make sense to interpret [] as a collection in the replacement part since that construct is intended to match a single character within the collection. As such, it just assumes it's the literal characters in the replacement part.
  4. See the explanation above.
  5. As stated above, the brackets aren't considered to be a "word character" by default, so I think it's choking on the fact that it's looking for a literal ] followed by the end of word boundary which doesn't really make sense. I'm not 100% sure about this part, though (my experimentation had some odd results).
  6. In this case the brackets around the 2 are used to specify a collection of just one character, so it finds the 2 (which is considered a "word character") and then replaces it with the [1].
7
  • Escaping the opening square bracket and closing square bracket works and your explanation that \< expects a word character after it and \> expects a word character before it is the reason I get the "Pattern not found" error when I escape the square brackets that come after the escape sequence for beginning of word and the escape sequence for end of word makes sense, but I don't understand the escape sequences around "2" in :%s/\[\zs2\ze\]/1. I assume that you are some how telling vim to search for "[2]" but only replace "2" but it would be useful if you explained what \zs and \ze do?
    – bit
    Jun 27, 2019 at 18:42
  • Your 4th paragraph is a very interesting explanation because I did not recognize that the first square bracket started the collection and the second square bracket ended the collection (I wrongly thought first square bracket and second square bracket specified the collection).
    – bit
    Jun 27, 2019 at 19:30
  • Correct me if I'm wrong but now I understand that after an opening [ everything until the next closing ] specifies a collection I assume a collection matches any of the enclosed characters which means I expected :%s/[[2]]/[1] to match both "[" and "2". Are you saying a collection matches any single character in the collection (i.e. matches only one character in the collection), or in other words characters in a collection can be imagined to be separated with an OR logical operation? So :%s/[[2]]/[1] is basically '[' OR '2', AND ']'?
    – bit
    Jun 27, 2019 at 19:53
  • Why is it that the second ']' in :%s/[[2]]/[1] does not need to be escaped? Can you clarify what you mean by "Then the second ] is being being interpreted as a literal ] since it would otherwise be a syntax error since there is no opening [ to match it."?
    – bit
    Jun 27, 2019 at 19:56
  • Fixed the typo in the first question, it should say "Why does enclosing the entire pattern in the brackets (:%s/\<[[2]]\>/[1]/) return an E486: Pattern not found: \<[[2]]\> error"? You already explained that \< expects the next character to be a "word character" causes the "Patten not found error" when :%s/\<\[2\]\>/[1]/ is used but can you explain what causes the "Pattern not found error" when I don't escape the square brackets and wrongly placed the entire pattern in the collection because I misunderstood how a collection works i.e. :%s/\<[[2]]\>/[1]/?
    – bit
    Jun 27, 2019 at 20:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.