1 module qte5prs; 2 3 import asc1251 : fromUtf8to1251; 4 import std..string : translate, split, strip, indexOf, toLower; 5 private import std.stdio : File, writeln, readln; 6 7 // Должен быть объект, получающий на вход строку. Строка раскладываается 8 // на состовные слова и запоминается в поисковике. Список слов может 9 // быть найден (выдан) по входной последовательности 10 11 // ================================================================== 12 // CFinder - поисковик 13 // ================================================================== 14 // __________________________________________________________________ 15 16 struct s2 { 17 string c; // class 18 string p; // parent 19 } 20 21 class CFinder { //=> Поисковик. Помнит все слова в файле 22 // ______________________________________________________________ 23 this() { 24 } 25 // ______________________________________________________________ 26 ~this() { 27 } 28 // ______________________________________________________________ 29 private 30 struct fNode { //-> Узел списка гирлянды 31 string str; // Строка (слово) 32 //----------------- 33 un link; // Указатель на следующий или null 34 } 35 alias fNode* un; // Ссылка на узел цепочки 36 37 private 38 struct fClass { //-> Узел списка гирлянды для класса 39 string name; // Имя самого класса 40 string rawStr; // Исходная строка описания 41 uc parent; // Указатель на родителя или null 42 um metod; // указатель на цепочку методов 43 //----------------- 44 uc link; // Указатель на следующий или null 45 } 46 alias fClass* uc; // Ссылка на узел цепочки класса 47 48 private 49 struct fMetod { //-> Узел списка гирлянды для метода 50 string name; // Имя самого метода 51 string rawStr; // Исходная строка описания метода 52 uc parent; // Указатель на родителя или null 53 //----------------- 54 um link; // Указатель на следующий или null 55 um allLink; // Общий список методов 56 } 57 alias fMetod* um; // Ссылка на узел цепочки метода 58 // ______________________________________________________________ 59 um findMethod(uc klass, string metod) { //-> Найти или добавить метод 60 if(klass is null) return null; 61 um nod = klass.metod; // Начало цепочки 62 m1: if(nod is null) { // Цепочка пуста, вставка 1-го элемента 63 nod = new fMetod; nod.name = metod; 64 nod.link = klass.metod; nod.parent = klass; 65 klass.metod = nod; 66 nod.allLink = trapMetod; trapMetod = nod; 67 } else { // Цепочка не пуста, ищем ... 68 while(nod !is null) { 69 // writeln("compare: ", nameClass, " == ", nod.name); 70 if(nod.name == metod) { return nod; } 71 else { nod = nod.link; } 72 } 73 } 74 if(nod is null) goto m1; 75 return nod; 76 } 77 // ______________________________________________________________ 78 string[] getEqMet1(string w) { //-> Выдать массив похожих слов из методов 79 string[] rez; size_t dlw, dln; 80 if(w.length == 0) return rez; 81 um nod = trapMetod; 82 while(nod !is null) { 83 dlw = w.length; dln = nod.name.length; 84 if(dln >= dlw) { if(nod.name[0 .. dlw] == w) rez ~= nod.name; } 85 nod = nod.allLink; 86 } 87 return rez; 88 } 89 // ______________________________________________________________ 90 void printMet() { //-> Распечатать список всех методов 91 um nod = trapMetod; 92 while(nod !is null) { 93 writeln("[", nod.name, "] --> ", nod.rawStr); 94 nod = nod.allLink; 95 } 96 } 97 // ______________________________________________________________ 98 void printUc() { //-> Распечатать список всех классов 99 uc nod = trapClass; 100 while(nod !is null) { 101 writeln(nod, " --> [", nod.name, "][", (nod.parent is null) ? "" : nod.parent.name, "] - ", nod.rawStr); 102 um nodm = nod.metod; 103 while(nodm !is null) { 104 writeln("\t", nodm.name, " --> ", nodm.rawStr); 105 nodm = nodm.link; 106 } 107 nod = nod.link; 108 } 109 // nod = findClass("QFrame"); 110 // writeln("QFrame.Parent = ", nod.parent.name); 111 // writeln(nod.rawStr); 112 } 113 // ______________________________________________________________ 114 uc findClassOnly(string nameClass) { //-> Найти класс 115 uc nod = trapClass; 116 while(nod !is null) { 117 if(nod.name == nameClass) { return nod; } 118 else { nod = nod.link; } 119 } 120 return nod; 121 } 122 // ______________________________________________________________ 123 uc findClass(string nameClass) { //-> Найти или добавить класс 124 uc nod = trapClass; 125 m1: if(nod is null) { 126 nod = new fClass; nod.name = nameClass; 127 nod.link = trapClass; trapClass = nod; 128 // writeln("add: ", nameClass); 129 return nod; 130 } else { 131 while(nod !is null) { 132 // writeln("compare: ", nameClass, " == ", nod.name); 133 if(nod.name == nameClass) { return nod; } 134 else { nod = nod.link; } 135 } 136 } 137 if(nod is null) goto m1; 138 return nod; 139 } 140 // ______________________________________________________________ 141 // Получает на вход Класс:Родитель и ИсходнаяСтрокаКласса и сохраняет в цепочке классов 142 uc insertClassParent(s2 cp, string rewStr) { //-> Вставить в цепочку классов Класс:Родитель+ИсхСтрока 143 // 1 - Разобраться с Parent 144 uc uparent, uclass; 145 if(cp.p != "") uparent = findClass(cp.p); 146 if(cp.c == "") return null; 147 uclass = findClass(cp.c); 148 uclass.name = cp.c; uclass.rawStr = rewStr; uclass.parent = uparent; 149 lastClass = uclass; 150 return uclass; 151 } 152 // ______________________________________________________________ 153 private un[256] harrow; //-> гребенка, для 256 списков слов 154 dchar[dchar] transTable1; 155 un[] masAllWords; // Список указателей на все слова 156 uc trapClass; // Базовый якорь для цепочки Классов 157 um trapMetod; // Базовый якорь для цепочки всех Методов 158 uc lastClass; // Активный в данный момент класс 159 // ______________________________________________________________ 160 ubyte getC0(string s) { //-> Выдать индекс в гребенке 161 import std.utf: stride; 162 if(s.length == 0) return 0; 163 char[] w1251 = fromUtf8to1251(cast(char[])s[0..stride(s, 0)]); 164 return w1251[0]; 165 } 166 // ______________________________________________________________ 167 void addWord(string w) { //-> Добавить слово в список, если его нет 168 if(w.length == 0) return; 169 ubyte c0; 170 if(!isWordMono(w)) { 171 c0 = getC0(w); // Первая буква слова, как индекс цепочки в harrow 172 // Создадим узел цепочки (списка) 173 un nod = new fNode; nod.str = w; 174 masAllWords ~= nod; // Запомним это слово в полном списке слов 175 nod.link = harrow[c0]; // Вставим новый узел в цепочку 176 harrow[getC0(w)] = nod; // Подвесим обновленную цепочку 177 /* 178 // Надо идти по цепочке и удалять все производные слова 179 int dlw = w.length, dln; 180 un ukaz = nod, ukaz0 = ukaz; 181 while(!(ukaz is null)) { 182 dln = ukaz.str.length; 183 if(dln < dlw) { 184 // Найденное слово короче вставленного слова 185 if(w[0 .. dln] == ukaz.str) { 186 // Удаляем этот элемент 187 ukaz0.link = ukaz.link; delete ukaz; 188 if( !(ukaz0.link is null) ) { ukaz = ukaz0.link; } 189 else { break; } 190 } 191 } 192 ukaz0 = ukaz; ukaz = ukaz.link; 193 } 194 195 */ 196 197 } 198 } 199 // ______________________________________________________________ 200 bool isWordMono(string w) { //-> Есть целое слово в списке? 201 size_t dlw, dln; 202 bool rez; ubyte ind = getC0(w); un ukaz = harrow[ind]; 203 dlw = w.length; 204 while(!(ukaz is null)) { 205 dln = ukaz.str.length; 206 if(dln == dlw) { 207 if(ukaz.str == w) { 208 rez = true; break; 209 } 210 } 211 ukaz = ukaz.link; 212 } 213 return rez; 214 } 215 // ______________________________________________________________ 216 bool isWord(string w) { //-> Есть целое слово или производные в списке? 217 size_t dlw, dln; 218 bool rez; ubyte ind = getC0(w); un ukaz = harrow[ind]; 219 dlw = w.length; 220 while(!(ukaz is null)) { 221 dln = ukaz.str.length; 222 if(dln >= dlw) { 223 if(ukaz.str[0 .. dlw] == w) { 224 rez = true; break; 225 } 226 } 227 ukaz = ukaz.link; 228 } 229 return rez; 230 } 231 // ______________________________________________________________ 232 string[] getSubFromAll(string w) { //-> Выдать массив похожих слов из общего хранилища 233 string[] rez; 234 string sh = toLower(w); 235 foreach(el; masAllWords) { 236 string wrd = toLower(el.str); 237 if(indexOf(wrd, sh) >= 0) rez ~= el.str; 238 } 239 return rez; 240 } 241 // ______________________________________________________________ 242 string[] getEq(string w) { //-> Выдать массив похожих слов из хранилища 243 string[] rez; size_t dlw, dln; 244 if(w.length == 0) return rez; 245 ubyte ind = getC0(w); un ukaz = harrow[ind]; 246 while(!(ukaz is null)) { 247 dlw = w.length; dln = ukaz.str.length; 248 if(dln >= dlw) { if(ukaz.str[0 .. dlw] == w) rez ~= ukaz.str; } 249 ukaz = ukaz.link; 250 } 251 return rez; 252 } 253 // ______________________________________________________________ 254 void addLine(string line) { //-> Добавить строку в хранилище 255 // import std.stdio; 256 immutable string clearLine = strip(line); 257 if(clearLine == "") return; 258 dchar[dchar] transTable = [ 259 '(':' ', 260 ')':' ', 261 9:' ', 262 '*':' ', 263 ';':' ', 264 '.':' ', 265 '[':' ', 266 ']':' ', 267 ',':' ', 268 '"':' ', 269 '!':' ', 270 '/':' ', 271 '=':' ', 272 '\\':' ', 273 ':':' ', 274 '@':' ' 275 ]; 276 static import asc1251; 277 string zish = translate(clearLine, transTable); 278 auto msRaw = split(zish, ' '); 279 string[] ms; 280 foreach(el; msRaw) { if(el == "") continue; ms ~= el; } 281 // Нужно удалить пустышки 282 try { 283 foreach(i, string el; ms) { 284 if(el == "") continue; 285 // string z = cast(string)strip(el); 286 if(el.length > 2) addWord(el); 287 // Всё добавлено в список поиска, можно проверить на нужные 288 // мне строки 289 if((el == "class") && (i == 0)) { 290 insertClassParent(nameClass(zish), clearLine.dup); 291 continue; 292 } 293 if(el == "->") { 294 // writeln(lastClass.name, " --> [", nameMethod(zish), "] -- ", clearLine); 295 um met = findMethod(lastClass, nameMethod(zish)); 296 if(met !is null) { 297 met.rawStr = clearLine.dup; 298 } 299 continue; 300 } 301 /* 302 mar 303 if(i == ms.length - 1) continue; 304 uc fnod = findClassOnly(el); 305 if(fnod is null) continue; 306 writeln(fnod.name, " = ", ms[i+1], " --> ", clearLine.dup); 307 if(el == "new") { 308 if(i == 0) continue; 309 if(i == ms.length - 1) continue; 310 311 writeln("var=[", ms[i-1], "] class = [", ms[i+1],"] = ", ms); 312 continue; 313 // Нужна функция, которая выдаёт s2 = Переменная|Тип или пусто 314 // - Взять предыдущее и следующие за new слово. Если нет, то null 315 } 316 */ 317 } 318 } catch { 319 // writeln("catch: ", line); 320 // writeln("catch: ", ms); 321 } 322 323 324 // if( indexOf(line, "//->") > 0 ) { writeln(zish); 325 // } 326 // Есть: 327 // Class : Parent 328 // Method : Функция(арг, ...) { //-> Описание функции 329 } 330 // ______________________________________________________________ 331 s2 nameClass(string s) { //-> Промежуточная. Выдать имя класса и родителя из строки 332 s2 rez; 333 auto ms = split(s, ' '); 334 string[] arg; 335 foreach(i, string el; ms) { 336 if(el == "") continue; 337 arg ~= el; 338 } 339 // arg --> очищенный массив строк 340 if(arg[0] == "class") { 341 if(arg.length == 1) return rez; 342 if(arg.length == 2) { rez.c = arg[1]; rez.p = ""; return rez; } 343 if(arg.length == 3) { rez.c = arg[1]; 344 if(arg[2] == "{") { 345 rez.p = ""; 346 } else { 347 rez.p = arg[2]; 348 } 349 return rez; 350 } 351 if(arg[3] == "{") { // class Name: Parent { 352 rez.c = arg[1]; rez.p = arg[2]; 353 } else { 354 if(arg[2] == "{") { // class Name { 355 rez.c = arg[1]; rez.p = ""; 356 } 357 } 358 } 359 return rez; 360 } 361 // ______________________________________________________________ 362 string nameMethod(string s) { //-> Промежуточная. Выдать имя метода из строки 363 string rez; 364 auto ms = split(s, ' '); 365 string[] arg; 366 foreach(i, string el; ms) { 367 if(el == "") continue; 368 arg ~= el; 369 } 370 rez = arg[1]; 371 return rez; 372 } 373 // ______________________________________________________________ 374 void addFile(string nameFile) { //-> Добавить файл в хранилище 375 // writeln("parsing: ", nameFile); 376 File fileSrc = File(nameFile, "r"); 377 int ks; 378 try { 379 foreach(line; fileSrc.byLine()) { 380 try { 381 // Проверка на BOM 382 ks++; 383 // if(ks++ == 0) if(line.length>2 && line[0]==239 && line[1]==187 && line[2]==191) line = line[3 .. $].dup; 384 addLine(cast(string)line); 385 } catch { 386 writeln("Warning! Error parsing string: [", cast(string)strip(line), "]"); 387 } 388 } 389 } catch { 390 writeln("Error read file: ", nameFile); 391 readln(); 392 } 393 } 394 } 395 396 unittest { 397 CFinder finder1 = new CFinder(); 398 bool b1; 399 400 // Проверка работы поиска слов 401 finder1.addWord("Gena"); 402 b1 = finder1.isWordMono("Gena"); assert(b1 == true); 403 b1 = finder1.isWordMono("gena"); assert(b1 == false); 404 b1 = finder1.isWord("Gen"); assert(b1 == true); 405 b1 = finder1.isWord("gen"); assert(b1 == false); 406 407 string[] m; 408 m = finder1.getEq("Gen"); assert(m == ["Gena"]); 409 m = finder1.getEq("gen"); assert(m == []); 410 m = finder1.getSubFromAll("Gen"); assert(m == ["Gena"]); 411 m = finder1.getSubFromAll("gen"); assert(m == ["Gena"]); 412 m = finder1.getSubFromAll("len"); assert(m == []); 413 414 // Проверяем работу с Классами 415 CFinder.uc adr; 416 adr = finder1.findClass("CTest1"); assert(adr.name == "CTest1"); 417 }