How can I use Xcode's `Find and Replace` on Multiline blocks of text

蹲街弑〆低调 提交于 2020-01-01 17:56:51

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!