Задача. Сторонники языков Java и C++ часто спорят о том, какой язык лучше для решения олимпиадных задач. Одни говорят, что в Java есть масса полезных библиотек для работы со строками, хорошо реализованы механизмы чтения и вывода данных, а так же радует встроенные возможности для реализации длинной арифметики. С другой стороны, С++ является классическим языком, скорость выполнения программ благодаря существующим компиляторам (например, Intel Compiler 10.0) гораздо выше, чем у Java.
Но сейчас нас интересует лишь небольшие отличия, а именно соглашения, которыми пользуются программисты при описании имен переменных в Java и C++. Известно, что для понимания значений переменных часто используют английские слова или даже целые предложения, описывающие суть переменных, содержащих те или иные значения. Приведем ниже правила описания переменных, которыми руководствуются программисты, реализующие программы на Java и C++.
В языке Java принято первое слово, входящее в название переменной записывать с маленькой латинской буквы, следующее слово идет с большой буквы (только первая буква слова большая), слова не имеют разделителей и состоят только из латинских букв. Например, правильные записи переменных в Java могут выглядеть следующим образом: javaIdentifier, longAndMnemonicIdentifier, name,nEERC.
В языке C++ для описания переменных используются только маленькие латинские символы и символ «_», который отделяет непустые слова друг от друга. Примеры: java_identifier, long_and_mnemonic_identifier, name, n_e_e_r_c.
Вам требуется написать программу, которая преобразует переменную, записанную на одном языке в формат другого языка.
Входные данные
Во входном файле задано наименование переменной длиной не более [latex]100[/latex] символов.
Выходные данные
В выходной файл требуется вывести аналог имени переменной в другом языке. Т.е. если переменная представлена в формате Java, то следует перевести в формат C++ и наоборот. В том случае, когда имя переменной не соответствует ни одному из вышеописанных языков, следует вывести «Error!«.
Задача взята с сайта e-olymp.
Тесты
Test | Input | Output |
1 | java_word | javaWord |
2 | cppWorD | cpp_wor_d |
3 | simpleword | simpleword |
4 | two__underscores | Error! |
5 | _underscore_in_the_beginning | Error! |
6 | underscore_in_the_end_ | Error! |
7 | UppercaseInTheBeginning | Error! |
8 | mixed_Style | Error! |
Код программы
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 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
#include <iostream> #include <cstring> using namespace std; const int START = 0; //start state const int CONTINUE = 1; //common prefix identifier state const int JAVAWORD = 2; //2-4 intermediate states const int CPPWORD = 3; const int CPPDEL = 4; //CPP-delimeter const int JAVA = 5; //5-10 final states const int CPP = 6; const int UNIVERSAL = 7; const int JAVAERR = 8; //Error in JAVA const int CPPERR = 9; //Error in CPP const int ERROR = 10; char var[101]; char result[203] = {'\0'}; //fill the resulting string with zero code characters int reslen = 0; //the length of the resulting string int state; bool is_small(char c) //supporting function { return ('a'<= c && c <= 'z'); } bool is_big(char c) //supporting function { return ('A'<= c && c <= 'Z'); } bool is_underscore(char c) //supporting function { return (c == '_'); } int selection_of_style(char * var, size_t len) //determines preliminary type of string { char c=var[0]; state = START; if(is_small(c)) { state = CONTINUE; } if(is_big(c)) { state = ERROR; return state; } if(is_underscore(c)) { state = ERROR; return state; } for (int i=1; i<len; i++) { c=var[i]; if(is_small(c)) state = state; if(is_big(c)) { state = JAVAWORD; return state; } if(is_underscore(c)) { state = CPPWORD; return state; } } //if(state == CONTINUE) //in the end os the word we are still in the state CONTINUE state = UNIVERSAL; return state; } int is_java(char * var, size_t len)//check if the word is a correct java variable { for (int i=0; i<len; i++) { char c = var[i]; if(is_small(c)) { state = state; } if(is_big(c)) { state = state; } if(is_underscore(c)) { state = JAVAERR; return state; } } if(state == JAVAWORD) { state = JAVA; } return state; } int is_cpp(char * var, size_t len) //check if the word is a correct cpp variable { for (int i=0; i<len; i++) { char c = var[i]; if(is_small(c)) { if(state == CPPDEL) { state = CPPWORD; } else state = state; } if(is_big(c)) { state = JAVAERR; return state; } if(is_underscore(c)) { if(state == CPPDEL) { state = CPPERR; return state; } state = CPPDEL; } } if(state == CPPWORD) { state = CPP; } if(state == CPPDEL) //underscore in the end is an error too { state = CPPERR; } return state; } void java_to_cpp(char * var, size_t len) //function-translator { for(int i=0; i<len; i++) { char c = var[i]; if(is_small(c)) { result[reslen++] = var[i]; //append character to resulting string } if(is_big(c)) { result[reslen++] = '_'; result[reslen++] = var[i]+32; } } } void cpp_to_java(char * var, size_t len) //function-translator { for(int i=0; i<len; i++) { char c = var[i]; if(is_small(c)) { result[reslen++] = var[i]; } if(is_underscore(c)) { result[reslen++]=var[++i]-32; } } } int main() { cin >> var; size_t len = strlen(var); state = selection_of_style(var, len); if(state == ERROR) { cout << "Error!" << endl; return 0; } if(state == JAVAWORD) state = is_java(var,len); if(state == CPPWORD) state = is_cpp(var,len); if (state == UNIVERSAL) { cout << var << endl; return 0; } if(state == JAVAERR) { cout << "Error!" << endl; return 0; } if(state == CPPERR) { cout << "Error!" << endl; return 0; } if(state == JAVA) { java_to_cpp(var,len); cout << result; return 0; } if(state==CPP) { cpp_to_java(var,len); cout << result; return 0; } return 0; } |
Алгоритм
Чтобы осуществить перевод строки с одного языка программирования на другой, нам нужно для начала определить, к какому языку она принадлежит. Для решения этой подзадачи я использовала алгоритм, основанный на присваивании строке так называемого состояния — некоторой константы, которой соответствует определенная категория строк. В начальный момент все строки находятся в состоянии Start. Состояние меняется в процессе посимвольного анализа строки. После просмотра последнего символа мы получаем нужный результат.
Для удобства я изобразила этот алгоритм в виде схемы:
*круговая стрелочка означает, что мы остаемся в этом же состоянии.
*над стрелочками перехода указаны символы, после считывания которых этот переход осуществляется. Если ничего не указано, значит для перехода в следующее состояние достаточно считать любой символ, кроме символов, указанных над стрелочками альтернативных вариантов перехода. Такие обозначения удобны, если исключений больше, чем правил.
Когда мы считываем очередной символ, мы переходим в другое состояние либо остаемся в предыдущем. В состояние Error(отмечено красным) мы переходим, если считаем какую-любо последовательность символов, не подходящую ни под один из стандартов.
Отдельно следует поговорить о состоянии CPP delimeter. Оно используется для контроля количества подчеркиваний. Если в нашей предполагаемой С++ переменной встречается подчеркивание, ей сразу же присваивается данное состояние, чтобы, при наличии второго подчеркивания сразу же перевести ее в состояние Error in CPP.
Финальные состояния отмечены зеленым цветом. В них мы переходим только после окончания строки непосредственно из предыдущего состояния. Переход в состояние Universal означает, что исходная строка состоит исключительно из маленьких букв и подходит как для языка Java, так и для C++.
Определив стандарт, к которому принадлежит переменная, мы вызываем блок перевода. Результат всегда записываем в отдельную переменную. В случае Java мы снова последовательно перебираем все символы строки и заменяем каждую встретившуюся большую букву на подчеркивание и эту же букву в маленьком регистре. Размер строки в этом случае увеличивается на количество больших букв в ее исходном варианте. В случае же С++ мы удаляем каждое подчеркивание, сдвигая все последующие символы, а первый из них переводим в большой регистр. Очевидно, что размер строки в этом случае будет уменьшен на количество подчеркиваний.
Хороший анализ, хорошая обстоятельная работа, молодец!