actions.qbk
来自「Boost provides free peer-reviewed portab」· QBK 代码 · 共 519 行 · 第 1/2 页
QBK
519 行
// Use val() to hold the shared_ptr by value: sregex rex = +( _d [ ++*val(pi) ] >> '!' ); // OK, rex holds a reference count to the integer. return rex; }In the above code, we use `xpressive::val()` to hold the shared pointer byvalue. That's not normally necessary because local variables appearing inactions are held by value by default, but in this case, it is necessary. Hadwe written the action as `++*pi`, it would have executed immediately. That'sbecause `++*pi` is not an expression template, but `++*val(pi)` is.It can be tedious to wrap all your variables in `ref()` and `val()` in yoursemantic actions. Xpressive provides the `reference<>` and `value<>` templatesto make things easier. The following table shows the equivalencies:[table reference<> and value<>[[This ...][... is equivalent to this ...]][[``int i = 0;sregex rex = +( _d [ ++ref(i) ] >> '!' );``][``int i = 0;reference<int> ri(i);sregex rex = +( _d [ ++ri ] >> '!' );``]][[``boost::shared_ptr<int> pi(new int(0));sregex rex = +( _d [ ++*val(pi) ] >> '!' );``][``boost::shared_ptr<int> pi(new int(0));value<boost::shared_ptr<int> > vpi(pi);sregex rex = +( _d [ ++*vpi ] >> '!' );``]]]As you can see, when using `reference<>`, you need to first declare a localvariable and then declare a `reference<>` to it. These two steps can be combinedinto one using `local<>`.[table local<> vs. reference<>[[This ...][... is equivalent to this ...]][[``local<int> i(0);sregex rex = +( _d [ ++i ] >> '!' );``][``int i = 0;reference<int> ri(i);sregex rex = +( _d [ ++ri ] >> '!' );``]]]We can use `local<>` to rewrite the above example as follows: local<int> i(0); std::string str("1!2!3?"); // count the exciting digits, but not the // questionable ones. sregex rex = +( _d [ ++i ] >> '!' ); regex_search(str, rex); assert( i.get() == 2 );Notice that we use `local<>::get()` to access the value of the localvariable. Also, beware that `local<>` can be used to create a danglingreference, just as `reference<>` can.[h3 Referring to Non-Local Variables]In the beginning of thissection, we used a regex with a semantic action to parse a string ofword/integer pairs and stuff them into a `std::map<>`. That required thatthe map and the regex be defined together and used before either couldgo out of scope. What if we wanted to define the regex once and use itto fill lots of different maps? We would rather pass the map into the_regex_match_ algorithm rather than embed a reference to it directly inthe regex object. What we can do instead is define a placeholder and usethat in the semantic action instead of the map itself. Later, when wecall one of the regex algorithms, we can bind the reference to an actualmap object. The following code shows how. // Define a placeholder for a map object: placeholder<std::map<std::string, int> > _map; // Match a word and an integer, separated by =>, // and then stuff the result into a std::map<> sregex pair = ( (s1= +_w) >> "=>" >> (s2= +_d) ) [ _map[s1] = as<int>(s2) ]; // Match one or more word/integer pairs, separated // by whitespace. sregex rx = pair >> *(+_s >> pair); // The string to parse std::string str("aaa=>1 bbb=>23 ccc=>456"); // Here is the actual map to fill in: std::map<std::string, int> result; // Bind the _map placeholder to the actual map smatch what; what.let( _map = result ); // Execute the match and fill in result map if(regex_match(str, what, rx)) { std::cout << result["aaa"] << '\n'; std::cout << result["bbb"] << '\n'; std::cout << result["ccc"] << '\n'; }This program displays:[pre123456]We use `placeholder<>` here to define `_map`, which stands in for a`std::map<>` variable. We can use the placeholder in the semantic action as ifit were a map. Then, we define a _match_results_ struct and bind an actual mapto the placeholder with "`what.let( _map = result );`". The _regex_match_ callbehaves as if the placeholder in the semantic action had been replaced with areference to `result`.[note Placeholders in semantic actions are not /actually/ replaced at runtimewith references to variables. The regex object is never mutated in any wayduring any of the regex algorithms, so they are safe to use in multiplethreads.]The syntax for late-bound action arguments is a little different if you areusing _regex_iterator_ or _regex_token_iterator_. The regex iterators acceptan extra constructor parameter for specifying the argument bindings. There isa `let()` function that you can use to bind variables to their placeholders.The following code demonstrates how. // Define a placeholder for a map object: placeholder<std::map<std::string, int> > _map; // Match a word and an integer, separated by =>, // and then stuff the result into a std::map<> sregex pair = ( (s1= +_w) >> "=>" >> (s2= +_d) ) [ _map[s1] = as<int>(s2) ]; // The string to parse std::string str("aaa=>1 bbb=>23 ccc=>456"); // Here is the actual map to fill in: std::map<std::string, int> result; // Create a regex_iterator to find all the matches sregex_iterator it(str.begin(), str.end(), pair, let(_map=result)); sregex_iterator end; // step through all the matches, and fill in // the result map while(it != end) ++it; std::cout << result["aaa"] << '\n'; std::cout << result["bbb"] << '\n'; std::cout << result["ccc"] << '\n';This program displays:[pre123456][h2 User-Defined Assertions]You are probably already familiar with regular expression /assertions/. InPerl, some examples are the [^^] and [^$] assertions, which you can use tomatch the beginning and end of a string, respectively. Xpressive lets youdefine your own assertions. A custom assertion is a contition which must betrue at a point in the match in order for the match to succeed. You can checka custom assertion with xpressive's _check_ function.There are a couple of ways to define a custom assertion. The simplest is touse a function object. Let's say that you want to ensure that a sub-expressionmatches a sub-string that is either 3 or 6 characters long. The followingstruct defines such a predicate: // A predicate that is true IFF a sub-match is // either 3 or 6 characters long. struct three_or_six { bool operator()(ssub_match const &sub) const { return sub.length() == 3 || sub.length() == 6; } };You can use this predicate within a regular expression as follows: // match words of 3 characters or 6 characters. sregex rx = (bow >> +_w >> eow)[ check(three_or_six()) ] ;The above regular expression will find whole words that are either 3 or 6characters long. The `three_or_six` predicate accepts a _sub_match_ that refersback to the part of the string matched by the sub-expression to which thecustom assertion is attached.[note The custom assertion participates in determining whether the matchsucceeds or fails. Unlike actions, which execute lazily, custom assertionsexecute immediately while the regex engine is searching for a match.]Custom assertions can also be defined inline using the same syntax as forsemantic actions. Below is the same custom assertion written inline: // match words of 3 characters or 6 characters. sregex rx = (bow >> +_w >> eow)[ check(length(_)==3 || length(_)==6) ] ;In the above, `length()` is a lazy function that calls the `length()` memberfunction of its argument, and `_` is a placeholder that receives the`sub_match`.Once you get the hang of writing custom assertions inline, they can bevery powerful. For example, you can write a regular expression thatonly matches valid dates (for some suitably liberal definition of theterm ["valid]). int const days_per_month[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 31, 31}; mark_tag month(1), day(2); // find a valid date of the form month/day/year. sregex date = ( // Month must be between 1 and 12 inclusive (month= _d >> !_d) [ check(as<int>(_) >= 1 && as<int>(_) <= 12) ] >> '/' // Day must be between 1 and 31 inclusive >> (day= _d >> !_d) [ check(as<int>(_) >= 1 && as<int>(_) <= 31) ] >> '/' // Only consider years between 1970 and 2038 >> (_d >> _d >> _d >> _d) [ check(as<int>(_) >= 1970 && as<int>(_) <= 2038) ] ) // Ensure the month actually has that many days! [ check( ref(days_per_month)[as<int>(month)-1] >= as<int>(day) ) ] ; smatch what; std::string str("99/99/9999 2/30/2006 2/28/2006"); if(regex_search(str, what, date)) { std::cout << what[0] << std::endl; }The above program prints out the following:[pre2/28/2006]Notice how the inline custom assertions are used to range-check the values forthe month, day and year. The regular expression doesn't match `"99/99/9999"` or`"2/30/2006"` because they are not valid dates. (There is no 99th month, andFebruary doesn't have 30 days.)[endsect]
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?