• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 ///////////////////////////////////////////////////////////////////////////////
2 // numbers.cpp
3 //
4 //  Copyright 2008 David Jenkins. Distributed under the Boost
5 //  Software License, Version 1.0. (See accompanying file
6 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 
8 #if defined(_MSC_VER)
9 //disbale warning C4996: 'std::xxx' was declared deprecated
10 # pragma warning(disable:4996)
11 #endif
12 
13 #include <iostream>
14 #include <string>
15 #include <map>
16 #include <boost/assign/list_of.hpp> // for 'map_list_of()'
17 #include <boost/xpressive/xpressive.hpp>
18 #include <boost/xpressive/regex_actions.hpp>
19 
20 ///////////////////////////////////////////////////////////////////////////////
21 // Match all named numbers in a string and return their integer values
22 //
23 // For example, given the input string:
24 //      "one two sixty three thousand ninety five eleven"
25 // the program will output:
26 //      "one = 1"
27 //      "two = 2"
28 //      "sixty three thousand ninety five = 63095"
29 //      "eleven = 11"
30 
example1()31 void example1()
32 {
33     using namespace boost::xpressive;
34     using namespace boost::assign;
35 
36     // initialize the maps for named numbers
37     std::map< std::string, int > ones_map =
38         map_list_of("one",1)("two",2)("three",3)("four",4)("five",5)
39         ("six",6)("seven",7)("eight",8)("nine",9);
40 
41     std::map< std::string, int > teens_map =
42         map_list_of("ten",10)("eleven",11)("twelve",12)("thirteen",13)
43         ("fourteen",14)("fifteen",15)("sixteen",16)("seventeen",17)
44         ("eighteen",18)("nineteen",19);
45 
46     std::map< std::string, int > tens_map =
47         map_list_of("twenty",20)("thirty",30)("fourty",40)
48         ("fifty",50)("sixty",60)("seventy",70)("eighty",80)("ninety",90);
49 
50     std::map< std::string, int > specials_map =
51         map_list_of("zero",0)("dozen",12)("score",20);
52 
53     // n is the integer result
54     local<long> n(0);
55     // temp stores intermediate values
56     local<long> temp(0);
57 
58     // initialize the regular expressions for named numbers
59     sregex tens_rx =
60         // use skip directive to skip whitespace between words
61         skip(_s)
62         (
63             ( a3 = teens_map )
64             |
65             ( a2 = tens_map ) >> !( a1 = ones_map )
66             |
67             ( a1 = ones_map )
68         )
69         [ n += (a3|0) + (a2|0) + (a1|0) ];
70 
71     sregex hundreds_rx =
72         skip(_s)
73         (
74             tens_rx >>
75             !(
76                 as_xpr("hundred")  [ n *= 100 ]
77                 >> !tens_rx
78              )
79         )
80         ;
81 
82     sregex specials_rx =    // regex for special number names like dozen
83         skip(_s)
84         (
85             // Note: this uses two attribues, a1 and a2, and it uses
86             // a default attribute value of 1 for a1.
87             ( !( a1 = ones_map ) >> ( a2 = specials_map ) )
88                 [ n = (a1|1) * a2 ]
89             >> !( "and" >> tens_rx )
90         )
91         ;
92 
93     sregex number_rx =
94         bow
95         >>
96         skip(_s|punct)
97         (
98             specials_rx // special numbers
99             |
100             (   // normal numbers
101                 !( hundreds_rx >> "million" ) [ temp += n * 1000000, n = 0 ]
102                 >>
103                 !( hundreds_rx >> "thousand" ) [ temp += n * 1000, n = 0 ]
104                 >>
105                 !hundreds_rx
106             )
107             [n += temp, temp = 0 ]
108         );
109 
110     // this is the input string
111     std::string str( "one two three eighteen twenty two "
112         "nine hundred ninety nine twelve "
113         "eight hundred sixty three thousand ninety five "
114         "sixty five hundred ten "
115         "two million eight hundred sixty three thousand ninety five "
116         "zero sixty five hundred thousand "
117         "extra stuff "
118         "two dozen "
119         "four score and seven");
120 
121     // the MATCHING results of iterating through the string are:
122     //      one  = 1
123     //      two  = 2
124     //      three  = 3
125     //      eighteen  = 18
126     //      twenty two  = 22
127     //      nine hundred ninety nine  = 999
128     //      twelve  = 12
129     //      eight hundred sixty three thousand ninety five  = 863095
130     //      sixty five hundred ten  = 6510
131     //      two million eight hundred sixty three thousand ninety five  = 2863095
132     //      zero = 0
133     //      sixty five hundred thousand = 6500000
134     //      two dozen = 24
135     //      four score and seven = 87
136     sregex_token_iterator cur( str.begin(), str.end(), number_rx );
137     sregex_token_iterator end;
138 
139     for( ; cur != end; ++cur )
140     {
141         if ((*cur).length() > 0)
142             std::cout << *cur << " = " << n.get() << '\n';
143         n.get() = 0;
144     }
145     std::cout << '\n';
146     // the NON-MATCHING results of iterating through the string are:
147     //      extra = unmatched
148     //      stuff = unmatched
149     sregex_token_iterator cur2( str.begin(), str.end(), number_rx, -1 );
150     for( ; cur2 != end; ++cur2 )
151     {
152         if ((*cur2).length() > 0)
153             std::cout << *cur2 << " = unmatched" << '\n';
154     }
155 }
156 
157 ///////////////////////////////////////////////////////////////////////////////
158 // main
main()159 int main()
160 {
161     std::cout << "\n\nExample 1:\n\n";
162     example1();
163 
164     std::cout << "\n\n" << std::flush;
165 
166     return 0;
167 }
168