Rewritten grep example program.

"touched" some of the sources to force regression tests to rebuild.
Split test code up some more to help msvc-stlport.


[SVN r26705]
This commit is contained in:
John Maddock
2005-01-15 12:29:59 +00:00
parent 1e48609cfd
commit 30acb7d2f8
17 changed files with 231 additions and 716 deletions

View File

@ -53,13 +53,10 @@
<P>Directory: <A href="../test/captures">libs/test/captures</A>.</P>
<P>Files: <A href="../test/captures/captures_test.cpp">captures_test.cpp</A>.</P>
<H3>Example programs</H3>
<H4>jgrep.exe</H4>
<P>A simple grep implementation, run with no command line options to find out its
usage. Look at <A href="../src/fileiter.cpp">fileiter.cpp</A>/fileiter.hpp and
the mapfile class to see an example of a "smart" bidirectional iterator that
can be used with boost.regex or any other STL algorithm.</P>
<P>Files: <A href="../example/jgrep/jgrep.cpp">jgrep.cpp</A>, <A href="../example/jgrep/main.cpp">
main.cpp</A>.</P>
<H4>grep</H4>
<P>A simple grep implementation, run with the -h command line option to find out
its usage.</P>
<P>Files: <A href="../example/grep/grep.cpp">grep.cpp</A></P>
<H4>timer.exe</H4>
<P>A simple interactive expression matching application, the results of all
matches are timed, allowing the programmer to optimize their regular

View File

@ -53,13 +53,10 @@
<P>Directory: <A href="../test/captures">libs/test/captures</A>.</P>
<P>Files: <A href="../test/captures/captures_test.cpp">captures_test.cpp</A>.</P>
<H3>Example programs</H3>
<H4>jgrep.exe</H4>
<P>A simple grep implementation, run with no command line options to find out its
usage. Look at <A href="../src/fileiter.cpp">fileiter.cpp</A>/fileiter.hpp and
the mapfile class to see an example of a "smart" bidirectional iterator that
can be used with boost.regex or any other STL algorithm.</P>
<P>Files: <A href="../example/jgrep/jgrep.cpp">jgrep.cpp</A>, <A href="../example/jgrep/main.cpp">
main.cpp</A>.</P>
<H4>grep</H4>
<P>A simple grep implementation, run with the -h command line option to find out
its usage.</P>
<P>Files: <A href="../example/grep/grep.cpp">grep.cpp</A></P>
<H4>timer.exe</H4>
<P>A simple interactive expression matching application, the results of all
matches are timed, allowing the programmer to optimize their regular

View File

@ -63,7 +63,7 @@ rule regex-test-run ( sources + : input * )
test-suite regex-examples :
[ regex-test-run timer/regex_timer.cpp <template>../build/msvc-stlport-tricky : $(BOOST_ROOT)/libs/regex/example/timer/input_script.txt ]
[ regex-test-run jgrep/jgrep.cpp jgrep/main.cpp : -n boost/ $(BOOST_ROOT)/boost/regex.hpp ]
[ regex-test-run grep/grep.cpp <lib>../../program_options/build/boost_program_options : -n -b $(BOOST_ROOT)/boost/regex.hpp $(BOOST_ROOT)/boost/type_traits.hpp ]
[ regex-test-run snippets/credit_card_example.cpp ]
[ regex-test-run snippets/mfc_example.cpp ]
[ regex-test-run snippets/icu_example.cpp ]

View File

@ -24,7 +24,7 @@ rule regex-test-run ( sources + : input * )
test-suite regex-examples :
[ regex-test-run timer/regex_timer.cpp : $(BOOST_ROOT)/libs/regex/example/timer/input_script.txt ]
[ regex-test-run jgrep/jgrep.cpp jgrep/main.cpp : -n boost/ $(BOOST_ROOT)/boost/regex.hpp ]
[ regex-test-run grep/grep.cpp ../../program_options/build//program_options : -n -b $(BOOST_ROOT)/boost/regex.hpp $(BOOST_ROOT)/boost/type_traits.hpp ]
[ regex-test-run snippets/credit_card_example.cpp ]
[ regex-test-run snippets/mfc_example.cpp ]
[ regex-test-run snippets/icu_example.cpp ]

212
example/grep/grep.cpp Normal file
View File

@ -0,0 +1,212 @@
/*
*
* Copyright (c) 2004
* Dr John Maddock
*
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <boost/program_options.hpp>
#include <boost/regex.hpp>
namespace po = boost::program_options;
int after_context;
int before_context;
bool print_byte_offset;
bool count_only;
std::string pattern;
bool print_non_matching_files;
bool files_only;
bool print_line_numbers;
boost::regex_constants::syntax_option_type flags = boost::regex_constants::basic;
boost::regex re;
boost::smatch what;
std::string current_file;
int file_count;
void process_stream(std::istream& is)
{
std::string line;
int match_found = 0;
int linenum = 1;
while(std::getline(is, line))
{
bool result = boost::regex_search(line, what, re);
if(result)
{
if(print_non_matching_files)
return;
if(files_only)
{
std::cout << current_file << std::endl;
return;
}
if(!match_found && !count_only && (file_count > 1))
{
std::cout << current_file << ":\n";
}
++match_found;
if(!count_only)
{
if(print_line_numbers)
{
std::cout << linenum << ":";
}
if(print_byte_offset)
{
std::cout << what.position() << ":";
}
std::cout << what[0] << std::endl;
}
}
++linenum;
}
if(count_only && match_found)
{
std::cout << match_found << " matches found in file " << current_file << std::endl;
}
else if(print_non_matching_files && !match_found)
{
std::cout << current_file << std::endl;
}
}
void process_file(const std::string& name)
{
current_file = name;
std::ifstream is(name.c_str());
if(is.bad())
{
std::cerr << "Unable to open file " << name << std::endl;
}
process_stream(is);
}
int main(int argc, char * argv[])
{
try{
po::options_description opts("Options");
opts.add_options()
("help,h", "produce help message")
//("after-context,A", po::value<int>(&after_context)->default_value(0), "Print arg lines of trailing context after matching lines. Places a line containing -- between contiguous groups of matches.")
//("before-context,B", po::value<int>(&before_context)->default_value(0), "Print arg lines of leading context before matching lines. Places a line containing -- between contiguous groups of matches.")
//("context,C", po::value<int>(), "Print arg lines of output context. Places a line containing -- between contiguous groups of matches.")
("byte-offset,b", "Print the byte offset within the input file before each line of output.")
("count,c", "Suppress normal output; instead print a count of matching lines for each input file. With the -v, --invert-match option (see below), count non-matching lines.")
("extended-regexp,E", "Interpret PATTERN as an POSIX-extended regular expression.")
("perl-regexp,P", "Interpret PATTERN as a Perl regular expression.")
//("regexp,e", po::value<std::string>(&pattern), "Use PATTERN as the pattern; useful to protect patterns beginning with -.")
("basic-regexp,G", "Interpret arg as a POSIX-basic regular expression (see below). This is the default.")
("ignore-case,i", "Ignore case distinctions in both the PATTERN and the input files.")
("files-without-match,L", "Suppress normal output; instead print the name of each input file from which no output would normally have been printed. The scanning will stop on the first match.")
("files-with-matches,l", "Suppress normal output; instead print the name of each input file from which output would normally have been printed. The scanning will stop on the first match.")
("line-number,n", "Prefix each line of output with the line number within its input file.")
;
// Hidden options, will be allowed both on command line and
// in config file, but will not be shown to the user.
po::options_description hidden("Hidden options");
hidden.add_options()
("input-file", po::value< std::vector<std::string> >(), "input file")
("input-pattern", po::value< std::string >(), "input file")
;
po::options_description cmdline_options;
cmdline_options.add(opts).add(hidden);
po::positional_options_description p;
p.add("input-pattern", 1);
p.add("input-file", -1);
po::variables_map vm;
store(po::command_line_parser(argc, argv).options(cmdline_options)/*.options(hidden)*/.positional(p).run(), vm);
notify(vm);
if (vm.count("help"))
{
std::cout << opts << "\n";
return 0;
}
if (vm.count("context"))
{
after_context = vm["context"].as< int >();
before_context = after_context;
}
if(vm.count("extended-regexp"))
{
flags = boost::regex_constants::extended;
}
if(vm.count("basic-regexp"))
{
flags = boost::regex_constants::basic;
}
if(vm.count("perl-regexp"))
{
flags = boost::regex_constants::perl;
}
if(vm.count("ignore-case"))
{
flags |= boost::regex_constants::icase;
}
if(vm.count("byte-offset"))
{
print_byte_offset = true;
}
if(vm.count("count"))
{
count_only = true;
}
if(vm.count("files-without-match"))
{
print_non_matching_files = true;
}
if(vm.count("files-with-matches"))
{
files_only = true;
}
if(vm.count("line-number"))
{
print_line_numbers = true;
}
if(vm.count("input-pattern"))
{
pattern = vm["input-pattern"].as< std::string >();
re.assign(pattern, flags);
}
else
{
std::cerr << "No pattern specified" << std::endl;
return 1;
}
if (vm.count("input-file"))
{
const std::vector<std::string>& files = vm["input-file"].as< std::vector<std::string> >();
file_count = files.size();
for(std::vector<std::string>::const_iterator i = files.begin(); i != files.end(); ++i)
{
process_file(*i);
}
}
else
{
// no input files, scan stdin instead:
process_stream(std::cin);
}
}
catch(const std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}

View File

@ -1,51 +0,0 @@
# very basic makefile for jgrep.exe
#
# Borland C++ tools
#
# BCROOT defines the root directory of your bc builder install
#
!ifndef BCROOT
BCROOT=$(MAKEDIR)\..
!endif
BCC32 = $(BCROOT)\bin\Bcc32.exe
LIBPATH=..\..\build\bcb5
IDE_LinkFLAGS32 = -L$(BCROOT)\LIB
LINKOPTS= -ap -Tpe -x
COMPOPTS= -O2 -tWM- -Vx -Ve -DSTRICT; -I$(BCROOT)\include;../../../../; -D_NO_VCL
jgrep.exe : jgrep.obj main.obj
$(BCC32) $(COMPOPTS) -e$@ -L$(LIBPATH) main.obj jgrep.obj
jgrep.obj : jgrep.cpp
$(BCC32) -c @&&|
$(COMPOPTS) -o$@ jgrep.cpp
|
main.obj : main.cpp
$(BCC32) -c @&&|
$(COMPOPTS) -o$@ main.cpp
|

View File

@ -1,51 +0,0 @@
# very basic makefile for jgrep.exe
#
# Borland C++ tools
#
# BCROOT defines the root directory of your bc builder install
#
!ifndef BCROOT
BCROOT=$(MAKEDIR)\..
!endif
BCC32 = $(BCROOT)\bin\Bcc32.exe
LIBPATH="..\..\build\bcb4"
IDE_LinkFLAGS32 = -L$(BCROOT)\LIB
LINKOPTS= -ap -Tpe -x
COMPOPTS= -O2 -tWM- -Vx -Ve -DSTRICT; -I$(BCROOT)\include;../../../../; -D_NO_VCL
jgrep.exe : jgrep.obj main.obj
$(BCC32) @&&|
$(COMPOPTS) -e$@ -L$(LIBPATH) main.obj jgrep.obj
|
jgrep.obj : jgrep.cpp
$(BCC32) -c @&&|
$(COMPOPTS) -o$@ jgrep.cpp
|
main.obj : main.cpp
$(BCC32) -c @&&|
$(COMPOPTS) -o$@ main.cpp
|

View File

@ -1,50 +0,0 @@
# very basic makefile for jgrep.exe
#
# Borland C++ tools
#
# BCROOT defines the root directory of your bc builder install
#
!ifndef BCROOT
BCROOT=$(MAKEDIR)\..
!endif
BCC32 = $(BCROOT)\bin\Bcc32.exe
LIBPATH=../../build/bcb5
IDE_LinkFLAGS32 = -L$(BCROOT)\LIB
LINKOPTS= -ap -Tpe -x
COMPOPTS= -O2 -tWM- -Vx -Ve -DSTRICT; -I$(BCROOT)\include;../../../../; -D_NO_VCL
jgrep.exe : jgrep.obj main.obj
$(BCC32) $(COMPOPTS) -e$@ -L..\..\build\bcb5 main.obj jgrep.obj
jgrep.obj : jgrep.cpp
$(BCC32) -c @&&|
$(COMPOPTS) -o$@ jgrep.cpp
|
main.obj : main.cpp
$(BCC32) -c @&&|
$(COMPOPTS) -o$@ main.cpp
|

View File

@ -1,32 +0,0 @@
# very basic makefile for jgrep
#
# GNU compiler g++
#
CXX= $(INCLUDES) -O2 -I../../../../ -I./ $(CXXFLAGS) $(LDFLAGS)
jgrep : jgrep.cpp main.cpp
g++ -ojgrep $(CXX) jgrep.cpp main.cpp -L../../build/gcc -lboost_regex $(LIBS)
debug : jgrep.cpp main.cpp
g++ -ojgrep -I../../../../ -I./ -g jgrep.cpp main.cpp -L../../build/gcc -lboost_regex_debug $(LIBS)

View File

@ -1,148 +0,0 @@
/*
*
* Copyright (c) 1998-2002
* Dr John Maddock
*
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
/*
* FILE jgrep.cpp
* VERSION see <boost/version.hpp>
*/
#include <stdio.h>
#include <algorithm>
#include <boost/regex.hpp>
#ifdef JM_OLD_IOSTREAM
#include <iostream.h>
#else
#include <iostream>
using std::cout;
using std::cin;
using std::cerr;
using std::endl;
#endif
#ifdef __BORLANDC__
# pragma hrdstop
#endif
#ifdef BOOST_REGEX_V3
#include <boost/regex/v3/fileiter.hpp>
#else
#include <boost/regex/v4/fileiter.hpp>
#endif
#include "jgrep.h"
#ifndef BOOST_REGEX_NO_FILEITER
//
// class ogrep_predicate
// outputs the results of regex_grep to screen:
template <class iterator, class Allocator >
class ogrep_predicate
{
unsigned int& lines;
const char* filename;
unsigned int last_line;
iterator end_of_storage, last_line_start;
public:
ogrep_predicate(unsigned int& i, const char* p, iterator start, iterator end) : lines(i), filename(p), last_line(-1), end_of_storage(end), last_line_start(start) {}
ogrep_predicate(const ogrep_predicate& o) : lines(o.lines), filename(o.filename), last_line(o.last_line), end_of_storage(o.end_of_storage), last_line_start(o.last_line_start) {}
bool operator () (const boost::match_results<iterator, Allocator>& i);
private:
void operator=(const ogrep_predicate&);
};
// ideally we'd ignor the allocator type and use a template member function
// to deel with the allocator type passed to regex_grep, unfortunately most
// compilers don't support this feature yet, so we'll have to be sure that
// the allocator passed to instances of this class match that used in our
// regular expression classes.
template <class iterator, class Allocator>
bool ogrep_predicate<iterator, Allocator>::operator()(const boost::match_results<iterator, Allocator>& i)
{
// if we haven't printed the filename yet, then do it now:
if(last_line == (unsigned int)-1)
{
cout << "File " << filename << ":" << endl;
last_line = 0;
}
// calculate which line we are on, by adding the number of newlines
// we've skipped in the last search:
unsigned int current_line = last_line + std::count(last_line_start, end_of_storage, '\n');
// if we haven't already printed this line out, then do it now:
if(last_line != current_line)
{
++lines;
last_line = current_line;
if(count_only == 0)
{
if(show_lines)
cout << current_line << "\t";
const char* nls = "\n";
iterator ptr = std::find_end(last_line_start, i[0].first, nls, nls+1);
++ptr;
iterator ptr2 = ptr;
while((ptr2 != end_of_storage) && (*ptr2 != '\n'))++ptr2;
while(ptr != ptr2)
{
cout.put(*ptr);
++ptr;
}
cout << endl;
}
}
// set the last line seen to the start of the current match:
last_line_start = i[0].first;
return true;
}
using namespace boost;
void process_grep(const char* file)
{
try{
mapfile f(file);
unsigned int count = 0;
ogrep_predicate<mapfile::iterator, boost::match_results<mapfile::iterator>::allocator_type> oi(count, file, f.begin(), f.end());
if(files_only)
{
bool ok;
boost::match_results<mapfile::iterator> m;
ok = regex_search(f.begin(), f.end(), m, e, match_not_dot_newline | match_not_dot_null);
if(ok)
cout << "File " << file << endl;
}
else
{
regex_grep(oi, f.begin(), f.end(), e, match_not_dot_newline | match_not_dot_null);
if(count)
{
if(verbose || count_only)
{
cout << count << " lines match" << endl;
return;
}
}
else if(verbose)
{
cout << "File " << file << "(" << f.size() << "bytes):" << endl << "0 lines match" << endl;
}
}
}
catch(const std::exception& e)
{
std::cerr << std::endl << e.what() << std::endl;
}
catch(...)
{
}
}
#endif

View File

@ -1,42 +0,0 @@
/*
*
* Copyright (c) 1998-2000
* Dr John Maddock
*
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
/*
* FILE jgrep.h
* VERSION see <boost/version.hpp>
*/
#ifndef _JGREP_H
#define _JGREP_H
#include <boost/regex.hpp>
typedef boost::basic_regex<char> re_type;
extern re_type e;
// flags for output:
extern bool use_case;
extern bool show_lines;
extern bool count_only;
extern bool files_only;
extern bool recurse;
extern bool regularexs;
extern bool words_only;
extern bool verbose;
void process_grep(const char* file);
#endif

View File

@ -1,289 +0,0 @@
/*
*
* Copyright (c) 1998-2002
* Dr John Maddock
*
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
/*
* FILE main.cpp
* VERSION see <boost/version.hpp>
*/
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <boost/regex.hpp>
#include <boost/regex/v4/fileiter.hpp>
#include "jgrep.h"
#ifndef BOOST_REGEX_NO_FILEITER
#ifdef BOOST_NO_STDC_NAMESPACE
namespace std{
using ::strcpy;
using ::strcat;
using ::sprintf;
}
#endif
re_type e;
//rei_type ei(a);
// flags for output:
bool use_case = true;
bool show_lines = false;
bool count_only = false;
bool files_only = false;
bool recurse = false;
bool regularexs = true;
bool words_only = false;
bool verbose = false;
void usage()
{
std::cout <<
"jgrep version 0.95\n"
"usage: jgrep [-options] expression file [files...]\n"
"\n"
"options can be one of the following:\n"
"\n"
"-c prints a count of the number of matching lines only\n"
"-d recurses through subdirectories for matching files\n"
"-i causes case to be ignored when matching\n"
"-l lists the files which contain a match only\n"
"-n displays the line numbers of matches\n"
"-r- causes the expression to be interpreted as a literal string and not\n"
" as a regular expression\n"
"-w searches for matches that are whole words only\n"
"-z verbose mode\n"
"\n"
"expression: a regular expression, or a literal string if -r- is specified\n"
"\n"
"files: one or more files to search, the names can contain the wildcard\n"
" characters ? and *\n" << std::endl;
}
void parse_switch(const char* flag)
{
++flag;
while(*flag)
{
switch(*flag)
{
case '-':
switch(*(flag-1))
{
case 'c':
count_only = false;
break;
case 'd':
recurse = false;
break;
case 'i':
use_case = false;
break;
case 'l':
files_only = false;
break;
case 'n':
show_lines = false;
break;
case 'r':
regularexs = false;
break;
case 'w':
words_only = false;
break;
case 'z':
verbose = false;
break;
default:
std::cout << "Undefined option -";
std::cout.put(*flag);
std::cout << std::endl;
}
// turn off prev character:
break;
case 'c':
count_only = true;
break;
case 'd':
recurse = true;
break;
case 'i':
use_case = false;
break;
case 'l':
files_only = true;
break;
case 'n':
show_lines = true;
break;
case 'r':
regularexs = true;
break;
case 'w':
words_only = true;
break;
case 'z':
verbose = true;
break;
case '?':
usage();
exit(0);
case '+':
break;
default:
std::cout << "Undefined option -";
std::cout.put(*flag);
std::cout << std::endl;
}
++flag;
}
}
using namespace boost;
void HandleFile(const char* wild)
{
using namespace boost;
file_iterator end;
file_iterator start(wild);
if(recurse)
{
// go through sub directories:
char buf[MAX_PATH];
std::strcpy(buf, start.root());
int rootlen = strlen(buf);
if(*buf == 0)
{
std::strcpy(buf, ".");
std::strcat(buf, directory_iterator::separator());
std::strcat(buf, "*");
}
else
{
std::strcat(buf, directory_iterator::separator());
std::strcat(buf, "*");
}
directory_iterator dstart(buf);
directory_iterator dend;
// now get the file mask bit of "wild":
const char* ptr = wild + rootlen;
if(*ptr) ++ptr;
while(dstart != dend)
{
std::sprintf(buf, "%s%s%s", dstart.path(), directory_iterator::separator(), ptr);
HandleFile(buf);
++dstart;
}
}
std::for_each(start, end, process_grep);
}
int done = 0;
void HandleArg(const char* arg)
{
using namespace boost;
if(*arg == '-')
{
parse_switch(arg);
return;
}
if(done == 0)
{
// parse regular expression
if(regularexs)
{
if(words_only == 0)
{
e.set_expression(arg, use_case ? regex::normal : regbase::normal | regbase::icase);
//ei.set_expression(arg);
}
else
{
char* buf = new char[std::strlen(arg) + 8];
std::sprintf(buf, "\\<%s\\>", arg);
e.set_expression(buf, use_case ? regex::normal : regbase::normal | regbase::icase);
//ei.set_expression(buf);
delete[] buf;
}
}
else
{
// we need to convert text to literal:
int len2 = std::strlen(arg);
int len = len2 * 5 + 6;
char buf[8];
char* buf2 = new char[len];
*buf2 = 0;
if(words_only)
std::strcpy(buf2, "\\<");
for(int j = 0; j < len2; ++j)
{
std::sprintf(buf, "\\0%o", int(arg[j]));
std::strcat(buf2, buf);
}
if(words_only)
std::strcat(buf2, "\\>");
e.set_expression(buf2, use_case ? regex::normal : regbase::normal | regbase::icase);
//ei.set_expression(buf2);
delete[] buf2;
}
done = 1;
return;
}
// if we get to here we have one or more file names to process:
++done;
HandleFile(arg);
}
int main(int argc, char * argv[])
{
for(int i = 1; i < argc; ++i)
HandleArg(argv[i]);
if(done < 2)
usage();
return 0;
}
#else
#include <iostream>
int main(int argc, char * argv[])
{
std::std::cout <<
"\n<note>\n"
"This functionality is not available on with this compiler on this platform.\n"
"</note>\n";
return 0;
}
#endif

View File

@ -1,18 +0,0 @@
#
# very simple makefile for Visual C++ 6 + STLPort 4
#
jgrep.exe: main.cpp jgrep.cpp jgrep.h
cl -GX -GR /Oityb1 /GF /Gy -MT -I..\..\..\..\ jgrep.cpp main.cpp /link /LIBPATH:..\..\build\vc6-stlport user32.lib

View File

@ -1,18 +0,0 @@
#
# very simple makefile for Visual C++ 6
#
jgrep.exe: main.cpp jgrep.cpp jgrep.h
cl -GX -GR /Oityb1 /GF /Gy -I..\..\..\..\ jgrep.cpp main.cpp /link /LIBPATH:..\..\build\vc6

View File

@ -30,4 +30,3 @@
#include <boost/regex.hpp>
#endif

View File

@ -31,3 +31,5 @@
#endif

View File

@ -138,6 +138,8 @@ void test_sets()
}
void test_sets2b();
void test_sets2c();
void test_sets2()
{
using namespace boost::regex_constants;
@ -245,7 +247,12 @@ void test_sets2()
TEST_REGEX_SEARCH("[\\s]+", perl, "AB AB", match_default, make_array(2, 5, -2, -2));
TEST_INVALID_REGEX("[\\S]", perl);
TEST_REGEX_SEARCH("\\S+", perl, " abc ", match_default, make_array(2, 5, -2, -2));
test_sets2c();
}
void test_sets2c()
{
using namespace boost::regex_constants;
// and some Perl style properties:
TEST_REGEX_SEARCH("\\pl+", perl, "ABabcAB", match_default, make_array(2, 5, -2, -2));
TEST_REGEX_SEARCH("\\Pl+", perl, "abABCab", match_default, make_array(2, 5, -2, -2));