@@ -174,23 +174,33 @@ Option Option::parse(std::string const& option_description)
174
174
}
175
175
176
176
static const std::regex pattern {" (--|-)?(.*?)([,= ]|$)" };
177
- std::for_each (std::sregex_iterator{option_description.begin (), options_end, pattern},
178
- std::sregex_iterator{},
179
- [&](std::smatch const & match)
180
- {
181
- if (match[1 ].matched ) {
182
- if (match[1 ].length ()==1 ) {
183
- shortOption = " -" + match[2 ].str ();
184
- } else {
185
- longOption = " --" + match[2 ].str ();
186
- }
187
- } else if (match[2 ].matched && match[2 ].length ()) {
188
- argcount = 1 ;
189
- } else {
190
- // delimeter
191
- }
192
- });
193
-
177
+ for (std::sregex_iterator i {option_description.begin (), options_end, pattern, std::regex_constants::match_not_null},
178
+ e{};
179
+ i != e;
180
+ ++i)
181
+ {
182
+ std::smatch const & match = *i;
183
+ if (match[1 ].matched ) { // [1] is optional.
184
+ if (match[1 ].length ()==1 ) {
185
+ shortOption = " -" + match[2 ].str ();
186
+ } else {
187
+ longOption = " --" + match[2 ].str ();
188
+ }
189
+ } else if (match[2 ].length () > 0 ) { // [2] always matches.
190
+ std::string m = match[2 ];
191
+ argcount = 1 ;
192
+ } else {
193
+ // delimeter
194
+ }
195
+
196
+ if (match[3 ].length () == 0 ) { // [3] always matches.
197
+ // Hit end of string. For some reason 'match_not_null' will let us match empty
198
+ // at the end, and then we'll spin in an infinite loop. So, if we hit an empty
199
+ // match, we know we must be at the end.
200
+ break ;
201
+ }
202
+ }
203
+
194
204
if (argcount) {
195
205
std::smatch match;
196
206
if (std::regex_search (options_end, option_description.end (),
@@ -537,8 +547,16 @@ std::vector<T*> flat_filter(Pattern& pattern) {
537
547
}
538
548
539
549
std::vector<std::string> parse_section (std::string const & name, std::string const & source) {
550
+ // ECMAScript regex only has "?=" for a non-matching lookahead. In order to make sure we always have
551
+ // a newline to anchor our matching, we have to avoid matching the final newline of each grouping.
552
+ // Therefore, our regex is adjusted from the docopt Python one to use ?= to match the newlines before
553
+ // the following lines, rather than after.
540
554
std::regex const re_section_pattern {
541
- " (?:^|\\ n)([^\\ n]*" + name + " [^\\ n]*\\ n?(?:[ \\ t].*?(?:\\ n|$))*)" ,
555
+ " (?:^|\\ n)" // anchored at a linebreak (or start of string)
556
+ " ("
557
+ " [^\\ n]*" + name + " [^\\ n]*(?=\\ n?)" // a line that contains the name
558
+ " (?:\\ n[ \\ t].*?(?=\\ n|$))*" // followed by any number of lines that are indented
559
+ " )" ,
542
560
std::regex::icase
543
561
};
544
562
@@ -571,7 +589,7 @@ std::vector<std::string> longOptions(I iter, I end) {
571
589
std::vector<std::string> ret;
572
590
std::transform (iter, end,
573
591
std::back_inserter (ret),
574
- [](decltype (*iter) const & opt) { return opt->longOption (); });
592
+ [](typename I::reference opt) { return opt->longOption (); });
575
593
return ret;
576
594
}
577
595
0 commit comments