Sign in Join
Wiki copytemporary

macOS NSRegularExpression: what changed

Revision 2 to 3. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
1+[![macOSlogo.png](/wiki-images/1/15/macOSlogo.png)](</File:macOSlogo.png>)
2+
3+This article applies to [macOS](</Category:macOS> "Category:macOS") only.
4+
5+See also: [[Multiplatform Programming Guide]]
6+
7+
8+
19## Regular expressions
210
3-Regular expressions are patterns used to match specified alpha-numeric character combinations in the string data being searched.
11+Regular expressions are patterns used to match specified alpha-numeric character combinations in the string data being searched.
412
5-Each character in a regular expression (that is, each character in the string describing its pattern) is either a metacharacter or operator, having a special meaning, or a regular character that has a literal meaning.
13+Each character in a regular expression (that is, each character in the string describing its pattern) is either a metacharacter or operator, having a special meaning, or a regular character that has a literal meaning.
614
7-Regular expressions can be incredibly complex. Indeed, whole books have been written about them! For a gentle introduction to regular expressions, see this [O'Reilly article](https://www.oreilly.com/content/an-introduction-to-regular-expressions/).
15+Regular expressions can be incredibly complex. Indeed, whole books have been written about them! For a gentle introduction to regular expressions, see this [O'Reilly article](<https://www.oreilly.com/content/an-introduction-to-regular-expressions/>).
816
917## NSRegularExpression Overview
1018
11-The NSRegularExpression class has convenience methods for returning all the matches as an array, the total number of matches, the first match, and the range of the first match.
19+The NSRegularExpression class has convenience methods for returning all the matches as an array, the total number of matches, the first match, and the range of the first match.
1220
13-An individual match is represented by an instance of the NSTextCheckingResult class, which carries information about the overall matched range (via its range property), and the range of each individual capture group (via the rangeAtIndex method).
21+An individual match is represented by an instance of the NSTextCheckingResult class, which carries information about the overall matched range (via its range property), and the range of each individual capture group (via the rangeAtIndex method).
1422
15-NSRegularExpression conforms to the International Components for Unicode (ICU) specification for regular expressions.
23+NSRegularExpression conforms to the International Components for Unicode (ICU) specification for regular expressions.
1624
1725### Metacharacters
1826
19-For a comprehensive list of characters used by the NSRegularExpression class that have a special meaning in regular expression patterns, see the [ICU listing](https://unicode-org.github.io/icu/userguide/strings/regexp.html#regular-expression-metacharacters).
27+For a comprehensive list of characters used by the NSRegularExpression class that have a special meaning in regular expression patterns, see the [ICU listing](<https://unicode-org.github.io/icu/userguide/strings/regexp.html#regular-expression-metacharacters>).
2028
2129### Operators
2230
23-For a comprehensive list of operators used by the NSRegularExpression class, see the [ICU listing](https://unicode-org.github.io/icu/userguide/strings/regexp.html#regular-expression-operators).
31+For a comprehensive list of operators used by the NSRegularExpression class, see the [ICU listing](<https://unicode-org.github.io/icu/userguide/strings/regexp.html#regular-expression-operators>).
2432
2533## Example 1 - match a pattern
2634
27-In this fairly trivial and contrived code example, we use the **\d** metacharacter which matches a decimal digit and the **+** operator to match the preceding decimal digit one or more times. This pattern **\d+** aims to match all the occurrences of numbers in the search string which we then output using NSLog(). It uses the NSRegularExpression convenience methods for returning all of the matches in the search string as an array and the total number of matches.
35+In this fairly trivial and contrived code example, we use the **\d** metacharacter which matches a decimal digit and the **+** operator to match the preceding decimal digit one or more times. This pattern **\d+** aims to match all the occurrences of numbers in the search string which we then output using NSLog(). It uses the NSRegularExpression convenience methods for returning all of the matches in the search string as an array and the total number of matches.
2836
2937### Code
30-
31-``` pascal
38+```
3239Program regex_ex1;
33-
34-{$mode objfpc}{$H+}
35-{$modeswitch objectivec2}
36-
37-Uses
38- MacOSAll, CocoaAll, SysUtils;
39-
40-Var
41- srchStr : String;
42- patnStr : String;
43- myRegex : NSregularExpression;
44- matches : NSArray;
45- match : NSTextCheckingResult;
46- error : NSErrorPtr;
47-
48-Begin
49- error := Nil;
50- srchStr := 'I have 43 bags of 60 marbles.';
51- patnStr := '\d+';
52-
53- // Create a regular expression with given string and options
54- myRegex := NSregularExpression.regularExpressionWithPattern_options_error(NSStr(patnStr), NSRegularExpressionOptions(NSRegularExpressionCaseInsensitive), error);
55-
56- // Check creation of regular expression with given string and options
57- if(error <> Nil) then
58- begin
59- NSLog(NSStr('Regex creation error: %@'), error);
60- Exit;
61- end;
62-
63- // Save any matches in the given string in the matches array
64- matches := myRegex.matchesInString_options_range(NSStr(srchStr), 0, NSMakeRange(0, srchStr.Length));
65-
66- // Output
67- NSLog(NSStr('Search string: %@'), NSStr(srchStr));
68- NSLog(NSStr('Pattern string: %@'), NSStr(patnStr));
69- NSLog(NSStr('Number of matches: %lu'), myRegex.numberOfMatchesInString_options_range(NSStr(srchStr), 0, NSMakeRange(0, srchStr.Length)));
70-
71- for match in matches do
72- NSLog(NSStr('match: %@'), NSStr(srchStr).substringWithRange(match.rangeAtIndex(0)));
73-End.
40+
41+ {$mode objfpc}{$H+}
42+ {$modeswitch objectivec2}
43+
44+ Uses
45+ MacOSAll, CocoaAll, SysUtils;
46+
47+ Var
48+ srchStr : String;
49+ patnStr : String;
50+ myRegex : NSregularExpression;
51+ matches : NSArray;
52+ match : NSTextCheckingResult;
53+ error : NSErrorPtr;
54+
55+ Begin
56+ error := Nil;
57+ srchStr := 'I have 43 bags of 60 marbles.';
58+ patnStr := '\d+';
59+
60+ // Create a regular expression with given string and options
61+ myRegex := NSregularExpression.regularExpressionWithPattern_options_error(NSStr(patnStr), NSRegularExpressionOptions(NSRegularExpressionCaseInsensitive), error);
62+
63+ // Check creation of regular expression with given string and options
64+ if(error <> Nil) then
65+ begin
66+ NSLog(NSStr('Regex creation error: %@'), error);
67+ Exit;
68+ end;
69+
70+ // Save any matches in the given string in the matches array
71+ matches := myRegex.matchesInString_options_range(NSStr(srchStr), 0, NSMakeRange(0, srchStr.Length));
72+
73+ // Output
74+ NSLog(NSStr('Search string: %@'), NSStr(srchStr));
75+ NSLog(NSStr('Pattern string: %@'), NSStr(patnStr));
76+ NSLog(NSStr('Number of matches: %lu'), myRegex.numberOfMatchesInString_options_range(NSStr(srchStr), 0, NSMakeRange(0, srchStr.Length)));
77+
78+ for match in matches do
79+ NSLog(NSStr('match: %@'), NSStr(srchStr).substringWithRange(match.rangeAtIndex(0)));
80+ End.
7481```
7582
7683### Output
7784
78-The output from running the above code example is:
79-
80-```text
85+The output from running the above code example is:
86+```
81872021-06-12 21:05:46.335 regex_ex1[26138:232243] Search string: I have 43 bags of 60 marbles.
82-2021-06-12 21:05:46.336 regex_ex1[26138:232243] Pattern string: \d+
83-2021-06-12 21:05:46.336 regex_ex1[26138:232243] Number of matches: 2
84-2021-06-12 21:05:46.336 regex_ex1[26138:232243] match: 43
85-2021-06-12 21:05:46.336 regex_ex1[26138:232243] match: 60
88+ 2021-06-12 21:05:46.336 regex_ex1[26138:232243] Pattern string: \d+
89+ 2021-06-12 21:05:46.336 regex_ex1[26138:232243] Number of matches: 2
90+ 2021-06-12 21:05:46.336 regex_ex1[26138:232243] match: 43
91+ 2021-06-12 21:05:46.336 regex_ex1[26138:232243] match: 60
8692```
8793
8894### Code explanation
8995
90-The call to *regularExpressionWithPattern_options_error()* creates an NSRegularExpression object instance (myRegex) with the specified regular expression pattern and options.
91-
92-Options are specified using *NSRegularExpressionOptions()*. Note that by default NSRegularExpression performs case-sensitive searches, so we specified the NSRegularExpressionCaseInsensitive option for case-insenstive searches although, because we are dealing with digits above, this has no effect and we might as well have specified Nil in this example for no options.
96+The call to _regularExpressionWithPattern_options_error()_ creates an NSRegularExpression object instance (myRegex) with the specified regular expression pattern and options.
9397
94-Once we have the NSRegularExpression object, we can then use it for matching text among other operations.
98+Options are specified using _NSRegularExpressionOptions()_. Note that by default NSRegularExpression performs case-sensitive searches, so we specified the NSRegularExpressionCaseInsensitive option for case-insenstive searches although, because we are dealing with digits above, this has no effect and we might as well have specified Nil in this example for no options.
9599
96-After checking that the creation of the regular expression did not fail with an error, we call the *matchesInString_options_range()* method to search for any matches and store them in our NSArray (matches). This method takes our search string, any options (there are none here) and the range to search. The range is specified by giving *NSMakeRange()* the starting location to search in the string (0 = the beginning of the string) and the length of the search string.
100+Once we have the NSRegularExpression object, we can then use it for matching text among other operations.
97101
98-Next, we output the search string and pattern string, and then call the *numberOfMatchesInString_options_range()* method to determine the number of matches and output it.
102+After checking that the creation of the regular expression did not fail with an error, we call the _matchesInString_options_range()_ method to search for any matches and store them in our NSArray (matches). This method takes our search string, any options (there are none here) and the range to search. The range is specified by giving _NSMakeRange()_ the starting location to search in the string (0 = the beginning of the string) and the length of the search string.
99103
100-Finally, we iterate through the matches NSArray and output the matches individually. The call to *rangeAtIndex(0)* is the full match and is equivalent to simply calling *range*. The code for this looks a little obscure. Let me try to unpack it for you.
104+Next, we output the search string and pattern string, and then call the _numberOfMatchesInString_options_range()_ method to determine the number of matches and output it.
101105
102-If you just output the content of the matches NSArray you get this:
106+Finally, we iterate through the matches NSArray and output the matches individually. The call to _rangeAtIndex(0)_ is the full match and is equivalent to simply calling _range_. The code for this looks a little obscure. Let me try to unpack it for you.
103107
104-```text
108+If you just output the content of the matches NSArray you get this:
109+```
105110"<NSSimpleRegularExpressionCheckingResult: 0x14d617570>{7, 2}{<NSRegularExpression: 0x14d614fd0> \\d+ 0x1}",
106-"<NSSimpleRegularExpressionCheckingResult: 0x14d617610>{18, 2}{<NSRegularExpression: 0x14d614fd0> \\d+ 0x1}"
111+ "<NSSimpleRegularExpressionCheckingResult: 0x14d617610>{18, 2}{<NSRegularExpression: 0x14d614fd0> \\d+ 0x1}"
107112```
108113
109-Notice the {7, 2} and {18, 2} ranges which locate the first number at position 7 (counting from zero) in the search string with a length of 2 and the second number at position 18 with a length of 2. Knowing those ranges, you could use:
110-
111-``` pascal
114+Notice the {7, 2} and {18, 2} ranges which locate the first number at position 7 (counting from zero) in the search string with a length of 2 and the second number at position 18 with a length of 2. Knowing those ranges, you could use:
115+```
112116NSLog(NSStr('match: ''%@'''), NSStr(srchStr).substringWithRange(NSMakeRange(7, 2)));
113117```
114118
115-to output the first number. The *substringWithRange()* method extracts from our search string the substring that matches the specified range (7, 2). Clearer than mud? I hope so.
119+to output the first number. The _substringWithRange()_ method extracts from our search string the substring that matches the specified range (7, 2). Clearer than mud? I hope so.
116120
117121## Example 2 - match pattern groups
118122
119-This is similar to Example 1 above, except that this time we match groups of characters. Our search string is the same as before, but our pattern string has some added complexity. The pattern matches a decimal digit one or more times as before, but this time as a group which is delineated by using parentheses: **(/d+)**. Next, we use a point **.** to match any character and **?** to match zero or one times following the digit(s). Finally, we match the set of characters from a to z **(\[a-z\]+)** one or more times as a group.
123+This is similar to Example 1 above, except that this time we match groups of characters. Our search string is the same as before, but our pattern string has some added complexity. The pattern matches a decimal digit one or more times as before, but this time as a group which is delineated by using parentheses: **(/d+)**. Next, we use a point **.** to match any character and **?** to match zero or one times following the digit(s). Finally, we match the set of characters from a to z **([a-z]+)** one or more times as a group.
120124
121125### Code
122-
123-``` pascal
126+```
124127Program regex_ex2;
125-
126-{$mode objfpc}{$H+}
127-{$modeswitch objectivec2}
128-
129-Uses
130- MacOSAll, CocoaAll, SysUtils;
131-
132-Var
133- srchStr : String;
134- patnStr : String;
135- myRegex : NSregularExpression;
136- matches : NSArray;
137- match : NSTextCheckingResult;
138- error : NSErrorPtr;
139-
140-Begin
141- error := Nil;
142- srchStr := 'I have 43 Bags of 60 Marbles.';
143- patnStr := '(\d+).?([a-z]+)';
144-
145- // Create a regular expression with given string and options
146- myRegex := NSregularExpression.regularExpressionWithPattern_options_error(NSStr(patnStr), NSRegularExpressionOptions(NSRegularExpressionCaseInsensitive), error);
147-
148- // Check creation of regular expression with given string and options
149- if(error <> Nil) then
150- begin
151- NSLog(NSStr('Regex creation error: %@'), error);
152- Exit;
153- end;
154-
155- // Save any matches in the given string in the matches array
156- matches := myRegex.matchesInString_options_range(NSStr(srchStr), 0, NSMakeRange(0, srchStr.Length));
157-
158- // Output
159- NSLog(NSStr('Search string: %@'), NSStr(srchStr));
160- NSLog(NSStr('Pattern string: %@'), NSStr(patnStr));
161- NSLog(NSStr('Number of matches: %lu'), myRegex.numberOfMatchesInString_options_range(NSStr(srchStr), 0, NSMakeRange(0, srchStr.Length)));
162-
163- for match in matches do
164- begin
165- NSLog(NSStr('match(0): ''%@'''), NSStr(srchStr).substringWithRange(match.rangeAtIndex(0)));
166- NSLog(NSStr('match(1): ''%@'''), NSStr(srchStr).substringWithRange(match.rangeAtIndex(1)));
167- NSLog(NSStr('match(2): ''%@'''), NSStr(srchStr).substringWithRange(match.rangeAtIndex(2)));
168- end;
169-End.
128+
129+ {$mode objfpc}{$H+}
130+ {$modeswitch objectivec2}
131+
132+ Uses
133+ MacOSAll, CocoaAll, SysUtils;
134+
135+ Var
136+ srchStr : String;
137+ patnStr : String;
138+ myRegex : NSregularExpression;
139+ matches : NSArray;
140+ match : NSTextCheckingResult;
141+ error : NSErrorPtr;
142+
143+ Begin
144+ error := Nil;
145+ srchStr := 'I have 43 Bags of 60 Marbles.';
146+ patnStr := '(\d+).?([a-z]+)';
147+
148+ // Create a regular expression with given string and options
149+ myRegex := NSregularExpression.regularExpressionWithPattern_options_error(NSStr(patnStr), NSRegularExpressionOptions(NSRegularExpressionCaseInsensitive), error);
150+
151+ // Check creation of regular expression with given string and options
152+ if(error <> Nil) then
153+ begin
154+ NSLog(NSStr('Regex creation error: %@'), error);
155+ Exit;
156+ end;
157+
158+ // Save any matches in the given string in the matches array
159+ matches := myRegex.matchesInString_options_range(NSStr(srchStr), 0, NSMakeRange(0, srchStr.Length));
160+
161+ // Output
162+ NSLog(NSStr('Search string: %@'), NSStr(srchStr));
163+ NSLog(NSStr('Pattern string: %@'), NSStr(patnStr));
164+ NSLog(NSStr('Number of matches: %lu'), myRegex.numberOfMatchesInString_options_range(NSStr(srchStr), 0, NSMakeRange(0, srchStr.Length)));
165+
166+ for match in matches do
167+ begin
168+ NSLog(NSStr('match(0): ''%@'''), NSStr(srchStr).substringWithRange(match.rangeAtIndex(0)));
169+ NSLog(NSStr('match(1): ''%@'''), NSStr(srchStr).substringWithRange(match.rangeAtIndex(1)));
170+ NSLog(NSStr('match(2): ''%@'''), NSStr(srchStr).substringWithRange(match.rangeAtIndex(2)));
171+ end;
172+ End.
170173```
171174
172175### Output
173-
174-```text
176+```
1751772021-06-14 17:39:51.255 program2[7376:149163] Search string: I have 43 bags of 60 marbles.
176-2021-06-14 17:39:51.255 program2[7376:149163] Pattern string: (\d+).?([a-z]+)
177-2021-06-14 17:39:51.255 program2[7376:149163] Number of matches: 2
178-2021-06-14 17:39:51.255 program2[7376:149163] match(0): '43 Bags'
179-2021-06-14 17:39:51.255 program2[7376:149163] match(1): '43'
180-2021-06-14 17:39:51.255 program2[7376:149163] match(2): 'Bags'
181-2021-06-14 17:39:51.255 program2[7376:149163] match(0): '60 Marbles'
182-2021-06-14 17:39:51.255 program2[7376:149163] match(1): '60'
183-2021-06-14 17:39:51.255 program2[7376:149163] match(2): 'Marbles'
178+ 2021-06-14 17:39:51.255 program2[7376:149163] Pattern string: (\d+).?([a-z]+)
179+ 2021-06-14 17:39:51.255 program2[7376:149163] Number of matches: 2
180+ 2021-06-14 17:39:51.255 program2[7376:149163] match(0): '43 Bags'
181+ 2021-06-14 17:39:51.255 program2[7376:149163] match(1): '43'
182+ 2021-06-14 17:39:51.255 program2[7376:149163] match(2): 'Bags'
183+ 2021-06-14 17:39:51.255 program2[7376:149163] match(0): '60 Marbles'
184+ 2021-06-14 17:39:51.255 program2[7376:149163] match(1): '60'
185+ 2021-06-14 17:39:51.255 program2[7376:149163] match(2): 'Marbles'
184186```
185187
186188### Code explanation
187189
188-The explanation is pretty much the same as for Example 1, except that:
190+The explanation is pretty much the same as for Example 1, except that:
189191
190-1\) The NSRegularExpressionCaseInsensitive option for case-insenstive searches now has a use. We specified the set of lowercase characters a to z, but because of the option we matched the words Bags and Marbles with initial capital letters.
192+1) The NSRegularExpressionCaseInsensitive option for case-insenstive searches now has a use. We specified the set of lowercase characters a to z, but because of the option we matched the words Bags and Marbles with initial capital letters.
191193
192-2\) The call to *rangeAtIndex(0)* or the equivalent *range* matches the full pattern; the call to *rangeAtIndex(1)* matches the first group of digits that we specified; and the call to *rangeAtIndex(2)* matches the second group of characters that we specified.
194+2) The call to _rangeAtIndex(0)_ or the equivalent _range_ matches the full pattern; the call to _rangeAtIndex(1)_ matches the first group of digits that we specified; and the call to _rangeAtIndex(2)_ matches the second group of characters that we specified.
193195
194196## Example 3 - replace matched pattern
195197
196-This is similar to Example 1 above, except that this time we replace the decimal numbers matched by the regular expression with words instead of numbers. This is done two ways: one uses the *stringByReplacingMatchesInString_options_range_withTemplate()* method which returns a new string with the replacements and the other uses the *replaceMatchesInString_options_range_withTemplate()* method which replaces the matches in the original search string.
198+This is similar to Example 1 above, except that this time we replace the decimal numbers matched by the regular expression with words instead of numbers. This is done two ways: one uses the _stringByReplacingMatchesInString_options_range_withTemplate()_ method which returns a new string with the replacements and the other uses the _replaceMatchesInString_options_range_withTemplate()_ method which replaces the matches in the original search string.
197199
198200### Code
199-
200-``` pascal
201+```
201202Program regex_ex3;
202-
203-{$mode objfpc}{$H+}
204-{$modeswitch objectivec2}
205-
206-Uses
207- MacOSAll, CocoaAll, SysUtils;
208-
209-Var
210- srchStr : NSString;
211- srchStr2: NSMutableString;
212- patnStr : NSString;
213- templStr: NSString;
214- myRegex : NSregularExpression;
215- matches : NSArray;
216- match : NSTextCheckingResult;
217- numMatch: NSInteger;
218- error : NSErrorPtr;
219- count : ShortInt;
220-
221-Begin
222- error := Nil;
223- srchStr := NSStr('I have 43 Bags of 60 Marbles.');
224- srchStr2:= NSMutableString.stringWithString(srchStr);
225- patnStr := NSStr('\d+');
226-
227- // Create a regular expression with given string and options
228- myRegex := NSregularExpression.regularExpressionWithPattern_options_error(patnStr, NSRegularExpressionOptions(NSRegularExpressionCaseInsensitive), error);
229-
230- // Check creation of regular expression with given string and options
231- if(error <> Nil) then
232- begin
233- NSLog(NSStr('Regex creation error: %@'), error);
234- Exit;
235- end;
236-
237- // Save any matches in the given string in the matches array
238- matches := myRegex.matchesInString_options_range(srchStr, 0, NSMakeRange(0, srchStr.Length));
239-
240- // Save number of matches
241- numMatch := myRegex.numberOfMatchesInString_options_range(srchStr, 0, NSMakeRange(0, srchStr.Length));
242-
243- // Output
244- NSLog(NSStr('Search string: %@'), srchStr);
245- NSLog(NSStr('Pattern string: %@'), patnStr);
246- NSLog(NSStr('Number of matches: %lu'), numMatch);
247-
248- // Alternative 1: Using stringByReplacingMatchesInString_options_range_withTemplate()
249- for count := numMatch downto 1 do
250- begin
251- for match in matches do
203+
204+ {$mode objfpc}{$H+}
205+ {$modeswitch objectivec2}
206+
207+ Uses
208+ MacOSAll, CocoaAll, SysUtils;
209+
210+ Var
211+ srchStr : NSString;
212+ srchStr2: NSMutableString;
213+ patnStr : NSString;
214+ templStr: NSString;
215+ myRegex : NSregularExpression;
216+ matches : NSArray;
217+ match : NSTextCheckingResult;
218+ numMatch: NSInteger;
219+ error : NSErrorPtr;
220+ count : ShortInt;
221+
222+ Begin
223+ error := Nil;
224+ srchStr := NSStr('I have 43 Bags of 60 Marbles.');
225+ srchStr2:= NSMutableString.stringWithString(srchStr);
226+ patnStr := NSStr('\d+');
227+
228+ // Create a regular expression with given string and options
229+ myRegex := NSregularExpression.regularExpressionWithPattern_options_error(patnStr, NSRegularExpressionOptions(NSRegularExpressionCaseInsensitive), error);
230+
231+ // Check creation of regular expression with given string and options
232+ if(error <> Nil) then
252233 begin
253- if(srchStr.substringWithRange(match.range) = NSStr('43')) then
254- begin
255- templStr := NSStr('forty-three');
256- NSLog(NSStr('Match 1: %@ - Template string: %@'), srchStr.substringWithRange(match.range), templStr);
257- end;
258-
259- if(srchStr.substringWithRange(match.range) = NSStr('60')) then
260- begin
261- templStr := NSStr('sixty');
262- NSLog(NSStr('Match 2: %@ - Template string: %@'), srchStr.substringWithRange(match.range), templStr);
263- end;
264-
265- // Do string replacement
266- srchStr := myRegex.stringByReplacingMatchesInString_options_range_withTemplate(srchStr, NSRegularExpressionOptions(Nil), match.range, templStr);
234+ NSLog(NSStr('Regex creation error: %@'), error);
235+ Exit;
267236 end;
268-
269- // Save any matches in the new search string in the matches array
270- matches := myRegex.matchesInString_options_range(srchStr, 0, NSMakeRange(0, srchStr.Length));
271- end;
272-
273- // Output string with replacements
274- NSLog(NSStr('Result: %@'), srchStr);
275-
276- // Save any matches in the given string in the matches array
277- matches := myRegex.matchesInString_options_range(srchStr2, 0, NSMakeRange(0, srchStr2.Length));
278-
279- // Alternative 2: Using replaceMatchesInString_options_range_withTemplate()
280- for count := numMatch downto 1 do
281- begin
282- for match in matches do
237+
238+ // Save any matches in the given string in the matches array
239+ matches := myRegex.matchesInString_options_range(srchStr, 0, NSMakeRange(0, srchStr.Length));
240+
241+ // Save number of matches
242+ numMatch := myRegex.numberOfMatchesInString_options_range(srchStr, 0, NSMakeRange(0, srchStr.Length));
243+
244+ // Output
245+ NSLog(NSStr('Search string: %@'), srchStr);
246+ NSLog(NSStr('Pattern string: %@'), patnStr);
247+ NSLog(NSStr('Number of matches: %lu'), numMatch);
248+
249+ // Alternative 1: Using stringByReplacingMatchesInString_options_range_withTemplate()
250+ for count := numMatch downto 1 do
283251 begin
284- if(srchStr2.substringWithRange(match.range) = NSStr('43')) then
252+ for match in matches do
285253 begin
286- templStr := NSStr('forty-three');
287- NSLog(NSStr('Match 1: %@ - Template string: %@'), srchStr2.substringWithRange(match.range), templStr);
254+ if(srchStr.substringWithRange(match.range) = NSStr('43')) then
255+ begin
256+ templStr := NSStr('forty-three');
257+ NSLog(NSStr('Match 1: %@ - Template string: %@'), srchStr.substringWithRange(match.range), templStr);
258+ end;
259+
260+ if(srchStr.substringWithRange(match.range) = NSStr('60')) then
261+ begin
262+ templStr := NSStr('sixty');
263+ NSLog(NSStr('Match 2: %@ - Template string: %@'), srchStr.substringWithRange(match.range), templStr);
264+ end;
265+
266+ // Do string replacement
267+ srchStr := myRegex.stringByReplacingMatchesInString_options_range_withTemplate(srchStr, NSRegularExpressionOptions(Nil), match.range, templStr);
288268 end;
289- if(srchStr2.substringWithRange(match.range) = NSStr('60')) then
269+
270+ // Save any matches in the new search string in the matches array
271+ matches := myRegex.matchesInString_options_range(srchStr, 0, NSMakeRange(0, srchStr.Length));
272+ end;
273+
274+ // Output string with replacements
275+ NSLog(NSStr('Result: %@'), srchStr);
276+
277+ // Save any matches in the given string in the matches array
278+ matches := myRegex.matchesInString_options_range(srchStr2, 0, NSMakeRange(0, srchStr2.Length));
279+
280+ // Alternative 2: Using replaceMatchesInString_options_range_withTemplate()
281+ for count := numMatch downto 1 do
282+ begin
283+ for match in matches do
290284 begin
291- templStr := NSStr('sixty');
292- NSLog(NSStr('Match 2: %@ - Template string: %@'), srchStr2.substringWithRange(match.range), templStr);
293- end;
294-
295- // Do string replacement
296- myRegex.replaceMatchesInString_options_range_withTemplate(srchStr2, NSRegularExpressionOptions(Nil), match.range, templStr);
297- end;
298-
299- // Save any matches in the new search string in the matches array
300- matches := myRegex.matchesInString_options_range(srchStr2, 0, NSMakeRange(0, srchStr2.Length));
301- end;
302-
303- // Output string with replacements
304- NSLog(NSStr('Result: %@'), srchStr2);
305-End.
285+ if(srchStr2.substringWithRange(match.range) = NSStr('43')) then
286+ begin
287+ templStr := NSStr('forty-three');
288+ NSLog(NSStr('Match 1: %@ - Template string: %@'), srchStr2.substringWithRange(match.range), templStr);
289+ end;
290+ if(srchStr2.substringWithRange(match.range) = NSStr('60')) then
291+ begin
292+ templStr := NSStr('sixty');
293+ NSLog(NSStr('Match 2: %@ - Template string: %@'), srchStr2.substringWithRange(match.range), templStr);
294+ end;
295+
296+ // Do string replacement
297+ myRegex.replaceMatchesInString_options_range_withTemplate(srchStr2, NSRegularExpressionOptions(Nil), match.range, templStr);
298+ end;
299+
300+ // Save any matches in the new search string in the matches array
301+ matches := myRegex.matchesInString_options_range(srchStr2, 0, NSMakeRange(0, srchStr2.Length));
302+ end;
303+
304+ // Output string with replacements
305+ NSLog(NSStr('Result: %@'), srchStr2);
306+ End.
306307```
307308
308309### Output
309-
310-```text
310+```
3113112021-06-14 22:42:55.807 program3[9115:227765] Search string: I have 43 Bags of 60 Marbles.
312-2021-06-14 22:42:55.808 program3[9115:227765] Pattern string: \d+
313-2021-06-14 22:42:55.808 program3[9115:227765] Number of matches: 2
314-2021-06-14 22:42:55.808 program3[9115:227765] Match 1: 43 - Template string: forty-three
315-2021-06-14 22:42:55.808 program3[9115:227765] Match 2: 60 - Template string: sixty
316-2021-06-14 22:42:55.808 program3[9115:227765] Result: I have forty-three Bags of sixty Marbles.
317-2021-06-14 22:42:55.808 program3[9115:227765] Match 1: 43 - Template string: forty-three
318-2021-06-14 22:42:55.808 program3[9115:227765] Match 2: 60 - Template string: sixty
319-2021-06-14 22:42:55.808 program3[9115:227765] Result: I have forty-three Bags of sixty Marbles.
312+ 2021-06-14 22:42:55.808 program3[9115:227765] Pattern string: \d+
313+ 2021-06-14 22:42:55.808 program3[9115:227765] Number of matches: 2
314+ 2021-06-14 22:42:55.808 program3[9115:227765] Match 1: 43 - Template string: forty-three
315+ 2021-06-14 22:42:55.808 program3[9115:227765] Match 2: 60 - Template string: sixty
316+ 2021-06-14 22:42:55.808 program3[9115:227765] Result: I have forty-three Bags of sixty Marbles.
317+ 2021-06-14 22:42:55.808 program3[9115:227765] Match 1: 43 - Template string: forty-three
318+ 2021-06-14 22:42:55.808 program3[9115:227765] Match 2: 60 - Template string: sixty
319+ 2021-06-14 22:42:55.808 program3[9115:227765] Result: I have forty-three Bags of sixty Marbles.
320320```
321321
322322## Example 4 - rearrange matched pattern groups
323323
324-This is similar to Example 2 above, except that this time not only do we match groups of characters, we rearrange them. Our search string is different this time and represents a contact list. We are going to rearrange the format from Firstname, Lastname to the more sensible Lastname, Firstname and then enclose the contact number state area code in parentheses. To do this, our pattern string has some added complexity.
324+This is similar to Example 2 above, except that this time not only do we match groups of characters, we rearrange them. Our search string is different this time and represents a contact list. We are going to rearrange the format from Firstname, Lastname to the more sensible Lastname, Firstname and then enclose the contact number state area code in parentheses. To do this, our pattern string has some added complexity.
325325
326-The pattern matches the first word group as a group of word characters followed by a comma **(\w+),** and does exactly the same again for the second word group, and finally matches the two digits of the area code as a group **(\d{2})**. The curly braces enclosing the number **{2}** after the digit metacharacter specifies that we want to match exactly two digits which comprise the area code.
326+The pattern matches the first word group as a group of word characters followed by a comma **(\w+),** and does exactly the same again for the second word group, and finally matches the two digits of the area code as a group **(\d{2})**. The curly braces enclosing the number **{2}** after the digit metacharacter specifies that we want to match exactly two digits which comprise the area code.
327327
328-The template string rearranges the data groups by switching the order of the first two word groups and adding parentheses around the third group which comprises the area code number.
328+The template string rearranges the data groups by switching the order of the first two word groups and adding parentheses around the third group which comprises the area code number.
329329
330330### Code
331-
332-``` pascal
331+```
333332Program regex_ex4;
334-
335-{$mode objfpc}{$H+}
336-{$modeswitch objectivec2}
337-
338-Uses
339- MacOSAll, CocoaAll, SysUtils;
340-
341-Var
342- srchStr : NSString;
343- srchStr2: NSMutableString;
344- patnStr : NSString;
345- tmplStr : NSString;
346- myRegex : NSregularExpression;
347- matches : NSArray;
348- match : NSTextCheckingResult;
349- error : NSErrorPtr;
350-
351-Begin
352- error := Nil;
353- srchStr := NSStr('Firstname, Lastname, 02 9428 4687');
354- srchStr2:= NSMutableString.stringWithString(srchStr);
355- patnStr := NSStr('(\w+), (\w+), (\d{2})');
356- tmplStr := NSStr('$2, $1, ($3)');
357-
358- // Create a regular expression with given string and options
359- myRegex := NSregularExpression.regularExpressionWithPattern_options_error(patnStr, NSRegularExpressionOptions(NSRegularExpressionCaseInsensitive), error);
360-
361- // Check creation of regular expression with given string and options
362- if(error <> Nil) then
363- begin
364- NSLog(NSStr('Regex creation error: %@'), error);
365- Exit;
366- end;
367-
368- // Save any matches in the given string in the matches array
369- matches := myRegex.matchesInString_options_range(srchStr, 0, NSMakeRange(0, srchStr.Length));
370-
371- // Output
372- NSLog(NSStr('Search string: %@'), srchStr);
373- NSLog(NSStr('Pattern string: %@'), patnStr);
374- NSLog(NSStr('Template string: %@'), tmplStr);
375- NSLog(NSStr('Number of matches: %lu'), myRegex.numberOfMatchesInString_options_range(srchStr, 0, NSMakeRange(0, srchStr.Length)));
376-
377- for match in matches do
378- begin
379- NSLog(NSStr('match(1): %@'), srchStr.substringWithRange(match.rangeAtIndex(1)));
380- NSLog(NSStr('match(2): %@'), srchStr.substringWithRange(match.rangeAtIndex(2)));
381- NSLog(NSStr('match(3): %@'), srchStr.substringWithRange(match.rangeAtIndex(3)));
382- // Do the replacements
383- myRegex.replaceMatchesInString_options_range_withTemplate(srchStr2, NSRegularExpressionOptions(Nil), match.range, tmplStr);
384- end;
385-
386- NSLog(NSStr('Result: %@'), srchStr2);
387-End.
333+
334+ {$mode objfpc}{$H+}
335+ {$modeswitch objectivec2}
336+
337+ Uses
338+ MacOSAll, CocoaAll, SysUtils;
339+
340+ Var
341+ srchStr : NSString;
342+ srchStr2: NSMutableString;
343+ patnStr : NSString;
344+ tmplStr : NSString;
345+ myRegex : NSregularExpression;
346+ matches : NSArray;
347+ match : NSTextCheckingResult;
348+ error : NSErrorPtr;
349+
350+ Begin
351+ error := Nil;
352+ srchStr := NSStr('Firstname, Lastname, 02 9428 4687');
353+ srchStr2:= NSMutableString.stringWithString(srchStr);
354+ patnStr := NSStr('(\w+), (\w+), (\d{2})');
355+ tmplStr := NSStr('$2, $1, ($3)');
356+
357+ // Create a regular expression with given string and options
358+ myRegex := NSregularExpression.regularExpressionWithPattern_options_error(patnStr, NSRegularExpressionOptions(NSRegularExpressionCaseInsensitive), error);
359+
360+ // Check creation of regular expression with given string and options
361+ if(error <> Nil) then
362+ begin
363+ NSLog(NSStr('Regex creation error: %@'), error);
364+ Exit;
365+ end;
366+
367+ // Save any matches in the given string in the matches array
368+ matches := myRegex.matchesInString_options_range(srchStr, 0, NSMakeRange(0, srchStr.Length));
369+
370+ // Output
371+ NSLog(NSStr('Search string: %@'), srchStr);
372+ NSLog(NSStr('Pattern string: %@'), patnStr);
373+ NSLog(NSStr('Template string: %@'), tmplStr);
374+ NSLog(NSStr('Number of matches: %lu'), myRegex.numberOfMatchesInString_options_range(srchStr, 0, NSMakeRange(0, srchStr.Length)));
375+
376+ for match in matches do
377+ begin
378+ NSLog(NSStr('match(1): %@'), srchStr.substringWithRange(match.rangeAtIndex(1)));
379+ NSLog(NSStr('match(2): %@'), srchStr.substringWithRange(match.rangeAtIndex(2)));
380+ NSLog(NSStr('match(3): %@'), srchStr.substringWithRange(match.rangeAtIndex(3)));
381+ // Do the replacements
382+ myRegex.replaceMatchesInString_options_range_withTemplate(srchStr2, NSRegularExpressionOptions(Nil), match.range, tmplStr);
383+ end;
384+
385+ NSLog(NSStr('Result: %@'), srchStr2);
386+ End.
388387```
389388
390389### Output
391-
392-```text
390+```
3933912021-06-15 20:37:54.880 program4[23076:159228] Search string: Firstname, Lastname, 02 9428 4687
394-2021-06-15 20:37:54.880 program4[23076:159228] Pattern string: (\w+), (\w+), (\d{2})
395-2021-06-15 20:37:54.880 program4[23090:159932] Template string: $2, $1, ($3)
396-2021-06-15 20:37:54.881 program4[23076:159228] Number of matches: 1
397-2021-06-15 20:37:54.881 program4[23076:159228] match(1): Firstname
398-2021-06-15 20:37:54.881 program4[23076:159228] match(2): Lastname
399-2021-06-15 20:37:54.881 program4[23076:159228] match(3): 02
400-2021-06-15 20:37:54.881 program4[23076:159228] Result: Lastname, Firstname, (02) 9428 4687
392+ 2021-06-15 20:37:54.880 program4[23076:159228] Pattern string: (\w+), (\w+), (\d{2})
393+ 2021-06-15 20:37:54.880 program4[23090:159932] Template string: $2, $1, ($3)
394+ 2021-06-15 20:37:54.881 program4[23076:159228] Number of matches: 1
395+ 2021-06-15 20:37:54.881 program4[23076:159228] match(1): Firstname
396+ 2021-06-15 20:37:54.881 program4[23076:159228] match(2): Lastname
397+ 2021-06-15 20:37:54.881 program4[23076:159228] match(3): 02
398+ 2021-06-15 20:37:54.881 program4[23076:159228] Result: Lastname, Firstname, (02) 9428 4687
401399```
402400
403401## See also
404402
405-- [[macOS NSString Regular Expressions]].
406-- [[RegEx packages]] - cross platform.
403+ * [[macOS NSString Regular Expressions]].
404+ * [[RegEx packages]] \- cross platform.
407405
408406## External links
409407
410-- [Apple: NSRegularExpression](https://developer.apple.com/documentation/foundation/nsregularexpression).
408+ * [Apple: NSRegularExpression](<https://developer.apple.com/documentation/foundation/nsregularexpression>).
411409
412-- [ICU: Documentation](https://unicode-org.github.io/icu/).
410+ * [ICU: Documentation](<https://unicode-org.github.io/icu/>).
413411
414412---
415-*From the Free Pascal wiki, page "macOS NSRegularExpression", as it stood on 2021-08-07 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
413+*From the Free Pascal wiki, page "macOS NSRegularExpression", as the Internet Archive kept it on 2025-03-13, last changed on 2021-08-08. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history