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