summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/xpressive/example/numbers.cpp
blob: 4e591bbbe9267fb049022d7c18a1eb2df8fe0c56 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
///////////////////////////////////////////////////////////////////////////////
// numbers.cpp
//
//  Copyright 2008 David Jenkins. Distributed under 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)

#if defined(_MSC_VER)
//disbale warning C4996: 'std::xxx' was declared deprecated
# pragma warning(disable:4996)
#endif

#include <iostream>
#include <string>
#include <map>
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/xpressive/xpressive.hpp>
#include <boost/xpressive/regex_actions.hpp>

///////////////////////////////////////////////////////////////////////////////
// Match all named numbers in a string and return their integer values
//
// For example, given the input string:
//      "one two sixty three thousand ninety five eleven"
// the program will output:
//      "one = 1"
//      "two = 2"
//      "sixty three thousand ninety five = 63095"
//      "eleven = 11"

void example1()
{
    using namespace boost::xpressive;
    using namespace boost::assign;

    // initialize the maps for named numbers
    std::map< std::string, int > ones_map =
        map_list_of("one",1)("two",2)("three",3)("four",4)("five",5)
        ("six",6)("seven",7)("eight",8)("nine",9);

    std::map< std::string, int > teens_map =
        map_list_of("ten",10)("eleven",11)("twelve",12)("thirteen",13)
        ("fourteen",14)("fifteen",15)("sixteen",16)("seventeen",17)
        ("eighteen",18)("nineteen",19);

    std::map< std::string, int > tens_map =
        map_list_of("twenty",20)("thirty",30)("fourty",40)
        ("fifty",50)("sixty",60)("seventy",70)("eighty",80)("ninety",90);

    std::map< std::string, int > specials_map =
        map_list_of("zero",0)("dozen",12)("score",20);

    // n is the integer result
    local<long> n(0);
    // temp stores intermediate values
    local<long> temp(0);

    // initialize the regular expressions for named numbers
    sregex tens_rx =
        // use skip directive to skip whitespace between words
        skip(_s)
        (
            ( a3 = teens_map )
            |
            ( a2 = tens_map ) >> !( a1 = ones_map )
            |
            ( a1 = ones_map )
        )
        [ n += (a3|0) + (a2|0) + (a1|0) ];

    sregex hundreds_rx =
        skip(_s)
        (
            tens_rx >>
            !(
                as_xpr("hundred")  [ n *= 100 ]
                >> !tens_rx
             )
        )
        ;

    sregex specials_rx =    // regex for special number names like dozen
        skip(_s)
        (
            // Note: this uses two attribues, a1 and a2, and it uses
            // a default attribute value of 1 for a1.
            ( !( a1 = ones_map ) >> ( a2 = specials_map ) )
                [ n = (a1|1) * a2 ]
            >> !( "and" >> tens_rx )
        )
        ;

    sregex number_rx =
        bow
        >>
        skip(_s|punct)
        (
            specials_rx // special numbers
            |
            (   // normal numbers
                !( hundreds_rx >> "million" ) [ temp += n * 1000000, n = 0 ]
                >>
                !( hundreds_rx >> "thousand" ) [ temp += n * 1000, n = 0 ]
                >>
                !hundreds_rx
            )
            [n += temp, temp = 0 ]
        );

    // this is the input string
    std::string str( "one two three eighteen twenty two "
        "nine hundred ninety nine twelve "
        "eight hundred sixty three thousand ninety five "
        "sixty five hundred ten "
        "two million eight hundred sixty three thousand ninety five "
        "zero sixty five hundred thousand "
        "extra stuff "
        "two dozen "
        "four score and seven");

    // the MATCHING results of iterating through the string are:
    //      one  = 1
    //      two  = 2
    //      three  = 3
    //      eighteen  = 18
    //      twenty two  = 22
    //      nine hundred ninety nine  = 999
    //      twelve  = 12
    //      eight hundred sixty three thousand ninety five  = 863095
    //      sixty five hundred ten  = 6510
    //      two million eight hundred sixty three thousand ninety five  = 2863095
    //      zero = 0
    //      sixty five hundred thousand = 6500000
    //      two dozen = 24
    //      four score and seven = 87
    sregex_token_iterator cur( str.begin(), str.end(), number_rx );
    sregex_token_iterator end;

    for( ; cur != end; ++cur )
    {
        if ((*cur).length() > 0)
            std::cout << *cur << " = " << n.get() << '\n';
        n.get() = 0;
    }
    std::cout << '\n';
    // the NON-MATCHING results of iterating through the string are:
    //      extra = unmatched
    //      stuff = unmatched
    sregex_token_iterator cur2( str.begin(), str.end(), number_rx, -1 );
    for( ; cur2 != end; ++cur2 )
    {
        if ((*cur2).length() > 0)
            std::cout << *cur2 << " = unmatched" << '\n';
    }
}

///////////////////////////////////////////////////////////////////////////////
// main
int main()
{
    std::cout << "\n\nExample 1:\n\n";
    example1();

    std::cout << "\n\n" << std::flush;

    return 0;
}