问题
I have a large file with hundreds of blocks of text (parts of C++ method calls) that resemble the Current
block below and I wish to use Xcode’s Regular Expression replacement to change each one to resemble the Desired
block below, capturing values 0.89f, A name, 0.1, 0.5 and 2.
Note that both blocks start and end with new Zapp
and //d.p.’s to show
respectively so to save myself loads of manual editing I wish to use regex search and replace.
The main problem I face is the multi-line
nature of the blocks. If we ignore that for a moment, I have ALMOST performed a search and replace on the following single-line
blocks:
Current:
new Zapp (0.89f // defaultParameterValue , "A name" // name , 0.1 // min , 0.5 // max , 2 // d.p.'s to show
Desired:
new Zapp (NormalisableRange<float> (0.1, 0.5) ,NormalisableRange<float> (0.1, 0.5).convertTo0to1(0.89f) , "A name" // name , 2 // d.p.'s to show
The Find and Replace:
Find: Zapp\s+\((.*)\s+// defaultParameterValue\s+,\s+"(.*)"\s+\/\/\s+name\s+,\s+(.*)\s+\/\/\s+min\s+,\s+(.*)\s+\/\/\s+max\s+,\s+(.*)\s+\/\/\s+d.p.'s
Replace: Zapp (NormalisableRange<float> ($3, $4) ,NormalisableRange<float> ($3, $4).convertTo0to1($1) , "$2" // name , $5 // d.p.’s
This single-line solution has the problem that additional white-space is seen after capture 1 (1 space), capture 3 (4 spaces) and capture 5 (3 spaces), otherwise it works well:
I tried to eliminate the whitespace from capture 1 (0.89f), capture 3 (0.1) and capture 5 (2) using [^\s]+
but it didn't help so if anybody can point out the reason for that I'd be grateful.
I can, for what it's worth, search for upper
and lower
using \s+
but I can't put it all together to achieve the desired result.
I've seen some old posts online that suggest this task might not be possible with Xcode. If that is true, can anybody suggest an alternative approach that will get the job done?
回答1:
The reason is the .*
is too greedy and match the whitespace that could have been matched by the \s+
pattern but for this greedy subpattern.
Either use the lazy/reluctant .*?
:
Zapp\s+\((.*?)\s+// defaultParameterValue\s+,\s+"(.*)"\s+\/\/\s+name\s+,\s+(.*?)\s+\/\/\s+min\s+,\s+(.*?)\s+\/\/\s+max\s+,\s+(.*?)\s+\/\/\s+d.p.'s
See the regex demo
Or define the class for matching floats/integers [-+\w.]+
(a bit not precise, but will do since the expected value type is known) or double quoted literals ("([^"\\]*(?:\\.[^"\\]*)*)"
):
Zapp\s+\(([-+\w.]+)\s+// defaultParameterValue\s+,\s+"([^"\\]*(?:\\.[^"\\]*)*)"\s+\/\/\s+name\s+,\s+([-+\w.]+)\s+\/\/\s+min\s+,\s+([-+\w.]+)\s+\/\/\s+max\s+,\s+([-+\d.]+)\s+\/\/\s+d.p.'s
See another demo
回答2:
Please see Wiktor's answer. He gives two solutions with demos that satisfy the problem in general.
However, thanks to Rich’s answer Multi line search and replace tool, I discovered AppCode by JetBrains will indeed do a multi-line search and replace:
SEARCH:
new Zapp\s+\(([^\s]+)\s+// defaultParameterValue\n\s+"(.*)"\s+\/\/\s+name\s+, ([^\s]+)\s+// min\n,\s+([^\s]+)\s+// max\n,\s+([^\s]+)\s+// d.p.'s to show
REPLACE:
new Zapp (NormalisableRange<float> ($3, $4)\n\t ,NormalisableRange<float> ($3, $4).convertTo0to1($1)\n\t\t\t , "$2" // name\n\t\t\t , $5 // d.p.'s to show
来源:https://stackoverflow.com/questions/37083126/how-can-i-use-xcodes-find-and-replace-on-multiline-blocks-of-text