2012-04-10 4 views
1

Я разрабатываю программу, которая делает базовые вычисления с использованием слов вместо чисел. Например. пять + два будут выдавать семь.C++ Word-int to int

Программа становится более сложным, принимая вход, такие как two_hundred_one + five_thousand_six (201 + 5006)

Через оператора перегрузки методов, я разделить каждое число и назначить его на его собственный индекс массива.

два будут [0], сотни [1], а один - [2]. Затем массив перерабатывается для 5006.

Моя проблема заключается в том, чтобы выполнить фактический расчет, мне нужно преобразовать слова, хранящиеся в массиве, в фактические целые числа.

У меня есть константные строки массивы, такие как это, как библиотека слов:

const string units[] = { "", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; 

const string teens[] = { "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" }; 

const string tens[] = { "", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" }; 

Если мой «маркер» массив хранится в нем двести одна индекса 0, 1 и 2, я m не уверен, что лучший способ конвертировать их в ints будет включать в себя.

+0

Если все, что вы хотите, должно превратить индивидуальное числовое слово в целое число, то это достаточно просто. Просто сканируйте эти массивы в цикле for, пока не получите совпадение. Или вы можете использовать карту, как рекомендует Джесси. Разбор цельной фразы типа «тридцать две тысячи триста сорок два» более сложный. С какой проблемой вы хотите помочь? –

+0

Я пробовал многословные утверждения if, но то, что я нахожу самым сложным, - это номера подростков – Edge

+0

@AdrianRatnapala. Мне кажется, мне нужна помощь с несколькими номерами слов. – Edge

ответ

2

Часть трюка для меня заключалась в том, чтобы анализировать маркеры назад, а не вперед. И поддерживать масштабный коэффициент, когда вы возвращаетесь через токены. Для каждого токена вы либо добавляете текущее значение (масштабируемое текущим значением scalefactor), либо корректируете масштабный коэффициент, в зависимости от того, с каким токеном вы сталкиваетесь.

Вот моя реализация (некоторые биты не включены, и вам нужно будет добавить небольшую логику для обработки миллионов).

#include <vector> 
#include <string> 

#include <assert.h> 

int tokens_to_int(const std::vector<std::string> &s) 
{ 
    int scale = 1; 
    int rv=0; 
    for(
     std::vector<std::string>::const_reverse_iterator it = s.rbegin(); 
     it!=s.rend(); 
     ++it 
    ) 
    { 
    std::string cw = *it; 
    //Things that add to the current value 
    if(cw == "one") { rv += 1 * scale; } 
    if(cw == "two") { rv += 2 * scale; } 
    if(cw == "three") { rv += 3 * scale; } 
    if(cw == "four") { rv += 4 * scale; } 
    // ... 
    if(cw == "nine") { rv += 9 * scale; } 
    if(cw == "ten") { rv += 10 * scale; } 

    // Teens 
    if(cw == "eleven") { rv += 11 * scale; } 
    if(cw == "twelve") { rv += 12 * scale; } 
    // ... 
    if(cw == "nineteen") { rv += 19 * scale; } 

    // Multiples of 10 
    if(cw == "twenty") { rv += 20 * scale; } 
    if(cw == "thirty") { rv += 30 * scale; } 
    if(cw == "fourty") { rv += 40 * scale; } 
    // ... 
    if(cw == "ninety") { rv += 90 * scale; } 

    //Things that effect scale for following entries 
    if(cw == "hundred") { scale *= 100; } 
    if(cw == "thousand") { if(scale==100) { scale=1000; } else { scale*=1000; } } 
    } 

    return rv; 
} 

template<typename T> 
struct as_vec 
{ 
    as_vec<T>& operator()(const T & t) 
    { 
    v.push_back(t); 
    return *this; 
    } 

    std::vector<T> build() { return v; } 

    std::vector<T> v; 
}; 

int main() 
{ 
    assert(421 == tokens_to_int(as_vec<std::string>()("four")("hundred")("twenty")("one").build())); 
    assert(422 == tokens_to_int(as_vec<std::string>()("four")("hundred")("twenty")("two").build())); 
    assert(11000 == tokens_to_int(as_vec<std::string>()("eleven")("thousand").build())); 
    assert(21201 == tokens_to_int(as_vec<std::string>()("twenty")("one")("thousand")("two")("hundred")("one").build())); 
    assert(100001 == tokens_to_int(as_vec<std::string>()("one")("hundred")("thousand")("one").build())); 
    assert(101000 == tokens_to_int(as_vec<std::string>()("one")("hundred")("one")("thousand").build())); 
    assert(411201 == tokens_to_int(as_vec<std::string>()("four")("hundred")("eleven")("thousand")("two")("hundred")("one").build())); 
    assert(999999 == tokens_to_int(as_vec<std::string>()("nine")("hundred")("ninety")("nine")("thousand")("nine")("hundred")("ninety")("nine").build())); 
} 
+0

Это выглядит красиво, гораздо чище, чем то, что я пытался (после того, как вы согласились с необходимостью предварительной маркировки).Единственное беспокойство - это обнаружить бессмыслицу как «тысячу два девятнадцати». –

+0

О, мужик, большое вам спасибо, что вы спасли мне действительно дорогие часы! – DevtelSoftware

0

Я согласен с Джесси об использовании карты для отображения значений в массивах, и с этого момента вы будете в состоянии сделать что-то вроде:

mymap["two"] * mymap["hundred"] + mymap["one"] 

конечно вы должны быть осторожными случаям, как «пятьсот две тысячи пятьдесят семь», в этом случае вам придется проверить для частного случая, кроме подростков один:

const string temp[] = {"five","hundred","two","thousand","fifty","seven"}; 

int handleThree(int start) { 
    if(mymap[temp[start+ 3]] > 100) //check for special case, in which case you handle 4 words instead of three 
     return (myap[temp[start]] * mymap[temp[start+1]] + mymap[temp[start+2]]) * mymap[temp[start+3]]; 
    else 
     return mymap[temp[start]] * mymap[temp[start+1]] + handleTwo(start+2) 
} 

int handleTwo(int start) { 
    if(mymap[temp[start]]/10 == 1) //check if it's a teen, return teen value 
     return mymap[temp[start]] 
    if(mymap[temp[start+1]] > 90) //check for another special case, "five thousand one hundred and fifty seven", for example should use this case 
     return mymap[temp[start]] * mymap[temp[start+1]] 
    else 
     return mymap[temp[start]] + mymap[temp[start+1]]; 
} 

конечно, есть еще несколько случаев вам придется следить для (например, «пятьсот шестьдесят две тысячи тринадцать»), но это было бы зная ваше удовольствие и опыт обучения, чтобы помочь вам справиться с такими случаями, но я считаю, что этого должно быть достаточно, чтобы вы начали.

Кроме того, я не лучший на C++, поэтому приносим извинения за какие-либо проблемы с моим кодом, если вы их найдете, но из моего тестирования это сработало с основным циклом, который я написал (я обязательно его предоставил но я думаю, вам было бы полезно написать это сами)