2

I have a string in a JSON file which is repeated with different values for chance. I want to replace all of these blocks by moving the miss chance out of the attack array and into a separate property.

"attacks": [
  {
    "name": "miss",
    "chance": "0.25"
  },
  ...
]
"missChance": 0.25,
"attacks": [
  ...
]

I managed to write a (basic) search pattern that would find all of these bits of JSON, and had grouping so I would be able to pull out the chance:

/"attacks":\s*[\_s*{\_s*"name":\s*"miss",\_s*"chance":\s"\(0\.\d*\)"\_s*},

However, although this search pattern would find all of the occurrences I wanted to replace, when I use it in a substitute command it returns "Pattern not found". The substitute I was using was:

:%s/"attacks":\s*[\_s*{\_s*"name":\s*"miss",\_s*"chance":\s"\(0\.\d*\)"\_s*},/"missChance": \1^M"attacks": [/g

I have noticed that the error includes more of the search pattern than I expected; it looks like it's searching for everything after the second "/" separator for some reason. Why would the search be different in the substitute command to in a normal search?

This is the error: Pattern not found: "attacks":\s*[\_s*{\_s*"name":\s*"miss",\_s*"chance":\s"\(0\.\d*\)"\_s*},/"missChance": \1,^M"attacks": [/g

1
  • For the future, you may want to consider using a macro instead of a convoluted substitute. You can sequence the macro such that it starts with a normal search to get to where you need to be, so repeated uses of the macro is effectively identical to :s///g, but likely far less complicated to write.
    – ZeroKnight
    Apr 29, 2019 at 2:55

1 Answer 1

1

Try to escape the opening square bracket, otherwise the whole command becomes the pattern.

:%s/"attacks":\s*\[\_s*{\_s*"name":\s*"miss",\_s*"chance":\s"\(0\.\d*\)"\_s*},/"missChance": \1^M"attacks": [/g
                 ^

If you don't escape it, the pattern in this substitution command:

:%s/"attacks":\s*[\_s*{\_s*"name":\s*"miss",\_s*"chance":\s"\(0\.\d*\)"\_s*},/"missChance": \1^M"attacks": [/g

is not:

"attacks":\s*[\_s*{\_s*"name":\s*"miss",\_s*"chance":\s"\(0\.\d*\)"\_s*},

but instead:

"attacks":\s*[\_s*{\_s*"name":\s*"miss",\_s*"chance":\s"\(0\.\d*\)"\_s*},/"missChance": \1^M"attacks": [/g

This is explained at :h E769:

When the ']' is not there Vim will not give an error message but assume no collection is used. Useful to search for '['. However, you do get E769 for internal searching. And be aware that in a :substitute command the whole command becomes the pattern. E.g. ":s/[/x/" searches for "[/x" and replaces it with nothing. It does not search for "[" and replaces it with "x"!

Your Answer

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

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