@@ -174,23 +174,33 @@ Option Option::parse(std::string const& option_description)
174174 }
175175
176176 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+
194204 if (argcount) {
195205 std::smatch match;
196206 if (std::regex_search (options_end, option_description.end (),
@@ -537,8 +547,16 @@ std::vector<T*> flat_filter(Pattern& pattern) {
537547}
538548
539549std::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.
540554 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+ " )" ,
542560 std::regex::icase
543561 };
544562
@@ -571,7 +589,7 @@ std::vector<std::string> longOptions(I iter, I end) {
571589 std::vector<std::string> ret;
572590 std::transform (iter, end,
573591 std::back_inserter (ret),
574- [](decltype (*iter) const & opt) { return opt->longOption (); });
592+ [](typename I::reference opt) { return opt->longOption (); });
575593 return ret;
576594}
577595
0 commit comments