2

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.

Current Block

Desired Block

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:

Current Single-Line

new Zapp (0.89f // defaultParameterValue , "A name" // name , 0.1 // min , 0.5 // max , 2 // d.p.'s to show

Desired:

Desired Single-Line

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:

Comparison of Search and Replace output and ideal output

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.

enter image description here

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?

Dave Chambers
  • 2,483
  • 2
  • 32
  • 55

2 Answers2

3

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

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • Both your answers satisfy the question in general so I’ll mark this as the correct answer. Actually pasting your code into Xcode’s Find and Replace box fails to match the text but this seems to be a limitation with multi-line blocks in Xcode. I have provided an answer myself using AppCode which does allow a multi-line search term, just to help others that might use AppCode. Thanks for your answer, I learnt something. – Dave Chambers May 07 '16 at 14:15
0

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

Community
  • 1
  • 1
Dave Chambers
  • 2,483
  • 2
  • 32
  • 55