1 /*
2 19.03.2018 12:58 - Применен алгоритм Максима Шибнева для fromUtf8to1251 (3-x кратное ускорение)
3 01.12.2017 17:57 - Темплате на toCON
4 13.08.2017 6:32 - Проверка и ускорение cp1251 -- Utf-8 -- cp1251
5 21.04.2016 18:13 - Проверка ИНН на корректность
6 31.05.2014 7:36:58
7 Add x64
8 Repair LTrim and RTrim
9 */
10 /*
11 ё - 184 0451 d1-91
12 Ё - 168 0401 d0-81
13 » - 00BB
14 « - 00AB
15 */
16 module asc1251;
17
18 import std.ascii;
19 import std.conv;
20 import std.utf;
21
22
23 bool isDigit1251(char c) pure nothrow { return (mm1251[c] & tDigit) != 0; }
24
25 bool isLower1251E(char c) pure nothrow { return (mm1251[c] & tEl) != 0; }
26
27 bool isUpper1251E(char c) pure nothrow { return (mm1251[c] & tEu) != 0; }
28
29 bool isLower1251R(char c) pure nothrow { return (mm1251[c] & tRl) != 0; }
30
31 bool isUpper1251R(char c) pure nothrow { return (mm1251[c] & tRu) != 0; }
32
33 bool isLetters1251E(char c) pure nothrow { return (mm1251[c] & (tEu + tEl)) != 0; }
34
35 bool isLetters1251R(char c) pure nothrow { return (mm1251[c] & (tRu + tRl)) != 0; }
36
37 bool isLetters1251(char c) pure nothrow { return (mm1251[c] & (tRu + tRl + tEu + tEl)) != 0; }
38
39 bool isPrintLetters1251(char c) pure nothrow { return (mm1251[c] & (tPrint)) != 0; }
40
41 unittest {
42 foreach (char c; "0123456789")
43 assert(asc1251.isDigit1251(c));
44 foreach (char c; lowercase)
45 assert(asc1251.isLower1251E(c));
46 foreach (char c; uppercase)
47 assert(asc1251.isUpper1251E(c));
48 foreach (char c; lowercase1251R)
49 assert(asc1251.isLower1251R(c));
50 foreach (char c; uppercase1251R)
51 assert(asc1251.isUpper1251R(c));
52 foreach (char c; uppercase ~ lowercase)
53 assert(asc1251.isLetters1251E(c));
54 foreach (char c; uppercase1251R ~ lowercase1251R)
55 assert(asc1251.isLetters1251R(c));
56 }
57
58 char[] LTrim1251(char[] str) {
59 char[] rez;
60 if (str.length == 0)
61 return rez;
62 for (auto i = 0; i < str.length; i++) {
63 if (!isPrintLetters1251(str[i]))
64 continue;
65 rez = str[i .. $];
66 break;
67 }
68 return rez;
69 }
70
71 char[] RTrim1251(char[] str) {
72 char[] rez;
73 if (str.length == 0)
74 return rez;
75 for (auto i = str.length; i != 0; i--) {
76 if (!isPrintLetters1251(str[i - 1]))
77 continue;
78 rez = str[0 .. i];
79 break;
80 }
81 return rez;
82 }
83
84 char[] Trim1251(char[] str) {
85 return LTrim1251(RTrim1251(str));
86 }
87
88 unittest {
89 assert(LTrim1251(cast(char[]) "") == cast(char[]) "");
90 assert(RTrim1251(cast(char[]) "") == cast(char[]) "");
91 assert(LTrim1251(cast(char[]) " Hello ") == cast(char[]) "Hello ");
92 assert(RTrim1251(cast(char[]) " Hello ") == cast(char[]) " Hello");
93 assert(LTrim1251(cast(char[]) " " ~ uppercase1251R) == cast(char[]) uppercase1251R);
94 assert(LTrim1251(cast(char[]) " " ~ lowercase1251R) == cast(char[]) lowercase1251R);
95 assert(RTrim1251(lowercase1251R ~ cast(char[]) " ") == cast(char[]) lowercase1251R);
96 assert(Trim1251(cast(char[]) " " ~ "1234567890" ~ "\x0E\x0F") == cast(char[]) "1234567890");
97 assert(LTrim1251(cast(char[]) " " ~ cast(char[]) "1") == cast(char[]) "1");
98 }
99
100 char toUpper1251(char c) {
101 return isLower1251E(c) | isLower1251R(c) ? cast(char)(c - 32) : c;
102 }
103
104 char[] toUpper1251(char[] str) {
105 char[] rez;
106 foreach (char c; str) {
107 rez ~= toUpper1251(c);
108 }
109 return rez;
110 }
111
112 char toLower1251(char c) {
113 return isUpper1251E(c) | isUpper1251R(c) ? cast(char)(c + 32) : c;
114 }
115
116 char[] toLower1251(char[] str) {
117 char[] rez;
118 foreach (char c; str) {
119 rez ~= toLower1251(c);
120 }
121 return rez;
122 }
123
124 char[] toFio1251(char[] str) {
125 if (str.length == 0) {
126 return str;
127 } else {
128 if (str.length == 1) {
129 char[] rez;
130 return rez ~= toUpper1251(str[0]);
131 } else {
132 return toUpper1251(str[0]) ~ toLower1251(str[1 .. $]);
133 }
134 }
135 }
136
137 unittest {
138 assert(toUpper1251('a') == 'A');
139 foreach (char c; lowercase)
140 assert(toUpper1251(c) == std.ascii.toUpper(c));
141 foreach (char c; lowercase1251R)
142 assert(toUpper1251(c) == uppercase1251R[c - 224]);
143 assert(toUpper1251(cast(char[]) "hello[23]") == "HELLO[23]");
144 assert(toUpper1251(cast(char[]) "") == "");
145 assert(toLower1251(cast(char[]) "17(HELLO)") == "17(hello)");
146 assert(toFio1251(cast(char[]) "HELLO!!!") == "Hello!!!");
147 assert(toFio1251(cast(char[]) "") == "");
148 assert(toFio1251(cast(char[]) "a") == "A");
149 }
150
151 // Функция, возвращает подстроку используя разделитель.
152 char[] Split1251(char[] from, char rz, int poz) {
153 char[] rez;
154 int i, b, e, k;
155 auto dLfrom = from.length;
156 for (i = 0; i < dLfrom; i++) {
157 if (from[i] == rz) {
158 e = i;
159 if (k == poz) {
160 rez = from[b .. e]; // Есть начало и есть конец. Надо переписать
161 return rez;
162 } else {
163 b = i + 1;
164 k++;
165 }
166 }
167 }
168 if (poz == k)
169 rez ~= from[b .. $];
170 return rez;
171 }
172
173 unittest {
174 assert(Split1251(cast(char[]) "ABC|DEF", '|', 0) == "ABC");
175 assert(Split1251(cast(char[]) "ABC|DEF", '|', 1) == "DEF");
176 assert(Split1251(cast(char[]) "ABC|DEF", '|', 2) == "");
177 assert(Split1251(cast(char[]) "ABC|DEF", '#', 2) == "");
178 assert(Split1251(cast(char[]) "ABC|DEF", '#', 0) == "ABC|DEF");
179 }
180 // Шифрация-Дешифрация осуществляется в том же буфере в Win-1251 и AsciiZ
181 // sh - T - шифрация, F - дешифрция
182 // str - указатель на строку
183 void shifr(bool sh, char* str) {
184 char ch;
185 int z;
186
187 if (sh) {
188 z = -1;
189 } else {
190 z = +1;
191 }
192 for (char* i = str;; i++) {
193 ch = *i;
194 if (ch == 0)
195 break;
196 *i = cast(char)(ch + z);
197 }
198 }
199 /* // Шифрует строки utf-8
200 // T - зашифровать, F - расшифровать
201 string shifr8(bool sh, string str) {
202 string rez; ubyte b;
203 if(str.length == 0) return rez;
204 if(sh) {
205 for(int i; i != str.length; i++) {
206 b = cast(ubyte)str[i];
207 if(b > 31) rez ~= "B" ~ (cast(char)(str[i]-1)); else rez ~= "A" ~ (cast(char)(str[i]+1));
208 }
209 }
210 else {
211 for(int i; i != str.length; i+=2) {
212 b = cast(ubyte)str[i];
213 if(b == 66) rez ~= (cast(char)(str[i+1]+1)); else rez ~= (cast(char)(str[i+1]-1));
214 }
215 }
216 return rez;
217 }
218 */
219
220
221 string shifr8n(T)(bool sh, T inStr) {
222 string rez;
223 ubyte b;
224 string str = cast(string) inStr;
225 return str;
226 if (str.length == 0)
227 return rez;
228 if (sh) {
229 for (int i; i != str.length; i++) {
230 b = cast(ubyte) str[i];
231 if (b > 31)
232 rez ~= "B" ~ (cast(char)(str[i] - 1));
233 else
234 rez ~= "A" ~ (cast(char)(str[i] + 1));
235 }
236 } else {
237 for (int i; i != str.length; i += 2) {
238 b = cast(ubyte) str[i];
239 if (b == 66)
240 rez ~= (cast(char)(str[i + 1] + 1));
241 else
242 rez ~= (cast(char)(str[i + 1] - 1));
243 }
244 }
245 return rez;
246 }
247
248 // Проверка даты вида '27.12.2014' на корректность
249 // str = '27.12.2014'
250 // Return: T - коррктная дата
251 bool TestDate1251(char[] str) {
252 bool rez = true;
253 char[] s;
254 char r = '.';
255 if (str.length != 10)
256 return false;
257 s = Split1251(str, r, 0);
258 if (s.length != 2)
259 return false;
260 else {
261 if (!isDigit1251(s[0]) || !isDigit1251(s[1]))
262 return false;
263 int day = to!int(s);
264 if (!(day > 0 && day < 32))
265 return false;
266 }
267 s = Split1251(str, r, 1);
268 if (s.length != 2)
269 return false;
270 else {
271 if (!isDigit1251(s[0]) || !isDigit1251(s[1]))
272 return false;
273 int mes = to!int(s);
274 if (!(mes > 0 && mes < 13))
275 return false;
276 }
277 s = Split1251(str, r, 2);
278 if (s.length != 4)
279 return false;
280 else {
281 if (!isDigit1251(s[0]) || !isDigit1251(s[1]) || !isDigit1251(s[2]) || !isDigit1251(s[3]))
282 return false;
283 int yar = to!int(s);
284 if (!(yar > 1900 && yar < 3000))
285 return false;
286 }
287 return rez;
288 }
289
290 // Проверка на соответствие ФИО, 'Иванов А.Н.', 1 большая, остальные маленькие и в конце инициалы
291 bool isFioii1251(char[] str) {
292 bool rez = true;
293 bool b1 = true;
294 bool b2 = true;
295 if (str.length < 6)
296 return false;
297 if (!(isUpper1251E(str[0]) || isUpper1251R(str[0])))
298 return false;
299 if (!((str[$ - 1] == '.') && (str[$ - 3] == '.')))
300 return false;
301 if (!(isUpper1251E(str[$ - 2]) || isUpper1251R(str[$ - 2])))
302 return false;
303 if (!(isUpper1251E(str[$ - 4]) || isUpper1251R(str[$ - 4])))
304 return false;
305 if (!(str[$ - 5] == ' '))
306 return false;
307 if (str.length > 6)
308 foreach (char c; str[1 .. $ - 6]) {
309 if (!(isLower1251E(c) || isLower1251R(c)))
310 return false;
311 }
312 return rez;
313 }
314
315 // Проверка на соответствие ФИО, 'Иванов', 1 большая, остальные маленькие
316 bool isFio1251(char[] str) {
317 bool rez = true;
318 bool b1 = true;
319 bool b2 = true;
320 if (str.length == 0)
321 return false;
322 if (!(isUpper1251E(str[0]) || isUpper1251R(str[0])))
323 return false;
324 foreach (char c; str[1 .. $]) {
325 if (!(isLower1251E(c) || isLower1251R(c)))
326 return false;
327 }
328 return rez;
329 }
330 // Проверка на соответствие 987, целое число
331 bool isInt1251(char[] str) {
332 bool rez = true;
333 bool b1 = true;
334 bool b2 = true;
335 if (str.length == 0)
336 return false;
337 foreach (char c; str[0 .. $]) {
338 if (!isDigit(c))
339 return false;
340 }
341 return rez;
342 }
343
344 unittest {
345 assert(TestDate1251(cast(char[]) "12.10.1961") == true);
346 assert(TestDate1251(cast(char[]) "10.10.161") == false);
347 assert(TestDate1251(cast(char[]) "00.10.1621") == false);
348 assert(TestDate1251(cast(char[]) "31.10.1621") == false);
349 assert(TestDate1251(cast(char[]) "32.10.2001") == false);
350 assert(TestDate1251(cast(char[]) "31.12.1621") == false);
351 assert(TestDate1251(cast(char[]) "31.13.2621") == false);
352 assert(TestDate1251(cast(char[]) "31.13.3001") == false);
353 // ------------------
354 assert(isFio1251(cast(char[]) "Gena") == true);
355 assert(isFio1251(cast(char[]) "Ge na") == false);
356 assert(isFio1251(cast(char[]) "\xC3\xE5\xED\xE0") == true);
357 assert(isFio1251(cast(char[]) "GenA") == false);
358 assert(isFio1251(cast(char[]) "\xC3\xE5\xED\xC0") == false);
359 }
360
361 // Проверка правильности ИНН string[10]
362 bool tstINN(string s) {
363 string s1;
364 bool rez;
365 int[10] weights = [2, 4, 10, 3, 5, 9, 4, 6, 8, 0];
366 int summ;
367
368 if((s.length == 0) || (s.length > 10) ) return rez;
369 foreach(ch; s) {
370 if(!isDigit1251(ch)) return rez;
371 }
372 import std..string: format, strip;
373 import std.conv: to;
374 try {
375 s1 = format("%.10s", to!long(strip(s)));
376 } catch(Throwable) {
377 return rez; // Ошибка конвертации
378 }
379 if(s1 == "0000000000") return true;
380 // Перебор цифр и вычисление суммы
381 for(int i; i != 9; i++) {
382 auto digit = s1[i] - 48;
383 summ += digit * weights[i];
384 }
385 auto ost = summ % 11;
386 if (ost > 9) ost = ost % 10;
387 if (ost == (s1[9] - 48)) rez = true;
388 return rez;
389 }
390
391 unittest {
392 assert(tstINN("") == false);
393 assert(tstINN("0000000000") == true);
394 assert(tstINN("0") == true);
395 assert(tstINN("0000A00000") == false);
396 assert(tstINN("+000000000") == false);
397 assert(tstINN("9999999999") == false);
398 assert(tstINN("05911013765") == false);
399
400 assert(tstINN("5905033450") == true);
401 assert(tstINN("5913001268") == true);
402 assert(tstINN("6607000556") == true);
403 assert(tstINN("5911013765") == true);
404 }
405
406 char[] from1251toUtf8(char[] str) pure nothrow @trusted {
407 char[] rez;
408 foreach (char c1; str) rez ~= mm1251_Utf8[c1];
409 return rez;
410 }
411 string from1251toUtf8(T)(T str) pure nothrow {
412 char[] rez;
413 foreach (char c1; cast(char[])str) rez ~= mm1251_Utf8[c1];
414 return cast(string)rez;
415 }
416 T1 fromUtf8to1251(T1, T2)(T2 str) {
417 return to!(T1)(fromUtf8to1251(to!(char[])(str)));
418 }
419
420 pragma(inline) size_t utf8Length(char[] src) pure nothrow @trusted { size_t len; foreach (ref b; src) { if ((b & 0xC0) != 0x80) len++; } return len; }
421 char[] fromUtf8to1251(char[] str) pure
422 {
423 if (str.length == 0) return str;
424
425 auto ret = new char[str.utf8Length];
426 //auto ret = new char[str.length * 4];
427 //char prb;
428 size_t srcPos;
429 size_t dstPos;
430 size_t id;
431
432 while(srcPos < str.length) {
433 id = stride(str, srcPos);
434 switch (id) {
435 case 1:
436 ret[dstPos] = str[srcPos];
437 break;
438 case 2:
439 switch (str[srcPos]) {
440 case '\xD0':
441 immutable prb = tbl_xD0[(str[srcPos + 1]) - 129];
442 ret[dstPos] = ((prb == 0) ? '?' : prb);
443 break;
444 case '\xD1':
445 immutable prb = tbl_xD1[(str[srcPos + 1]) - 128];
446 ret[dstPos] = ((prb == 0) ? '2' : prb);
447 break;
448 case '\xD2':
449 switch (str[srcPos + 1]) {
450 case '\x91':
451 ret[dstPos] = cast(char)180;
452 break;
453 case '\x90':
454 ret[dstPos] = cast(char)165;
455 break;
456 default:
457 ret[dstPos] = cast(char)7;
458 break;
459 }
460 break;
461 case '\xD3':
462 break;
463 case '\xC2':
464 immutable prb = tbl_xC2[(str[srcPos + 1]) - 152];
465 ret[dstPos] = ((prb == 0) ? '3' : prb);
466 break;
467 default:
468 ret[dstPos] = '?';
469 break;
470 }
471 break;
472 case 3:
473 if (str[srcPos] == '\xE2') {
474 switch (str[srcPos + 1]) {
475 case '\x80':
476 immutable prb = tbl_x80[(str[srcPos + 2]) - 147];
477 ret[dstPos] = ((prb == 0) ? '?' : prb);
478 break;
479 case '\x82':
480 ret[dstPos] = ((str[srcPos + 2] == '\xAC') ? cast(char)136 : '?');
481 break;
482 case '\x84':
483 switch (str[srcPos + 2]) {
484 case '\x96':
485 ret[dstPos] = (cast(char)185);
486 break;
487 case '\xA2':
488 ret[dstPos] = (cast(char)153);
489 break;
490 default:
491 ret[dstPos] = '?';
492 break;
493 }
494 break;
495 default:
496 break;
497 }
498 }
499 break;
500 default: // 4, 5, 6
501 break;
502 } // switch (id)
503
504 srcPos += id;
505 dstPos++;
506 }
507
508 return ret;
509 }
510
511
512 unittest {
513 assert(from1251toUtf8(cast(char[]) "\xC3\xE5\xED\xE0") == "Гена");
514 assert(from1251toUtf8(cast(char[]) "Gena123") == "Gena123");
515
516 assert(fromUtf8to1251(cast(char[]) "Гена") == "\xC3\xE5\xED\xE0");
517 assert(fromUtf8to1251(cast(char[]) "Gena123") == "Gena123");
518 char[] g = [ 'G', 'e', 'n', 'a', '1', '2', '3' ];
519 assert(fromUtf8to1251!(char[])("Gena123") == g);
520 assert(fromUtf8to1251!(char[])("Гена") == "\xC3\xE5\xED\xE0");
521
522 }
523
524 char[] from1251to866(char[] str) {
525 if (str.length == 0) return str;
526 int dlStr = str.length;
527 auto ret = new char[dlStr]; for(int i; i != dlStr; i++) ret[i] = _1251_866[str[i]];
528 return ret;
529 }
530
531 string toCON(T)(T s) {
532 version (Windows) {
533 return to!string(from1251to866(fromUtf8to1251(cast(char[]) s)));
534 }
535 version (linux) {
536 return cast(string)s;
537 }
538 version (OSX) {
539 return cast(string)s;
540 }
541 }
542 string char1251toUtf8(char ch) {
543 return mm1251_Utf8[ch];
544 }
545
546 private:
547
548 const int sByte = ubyte.max + 1;
549
550 const tBad = 0; // Бяка
551 const tDigit = 1; // Цифра
552 const tEl = 2; // Анг Маленькие
553 const tEu = 4; // Анг Большие
554 const tPrint = 8; // Печатные
555 const tRl = 16; // Рус Маленькие
556 const tRu = 32; // Рус Большие
557
558 private immutable char[][sByte] mm1251_Utf8= [
559 /* 0 */
560 "\x00", /* 1 */ "\x01", /* 2 */ "\x02", /* 3 */ "\x03", /* 4 */ "\x04",/* 5 */
561 "\x05", /* 6 */ "\x06", /* 7 */ "\x07", /* 8 */ "\x08", /* 9 */ "\x09",/* 10 */
562 "\x0A", /* 11 */ "\x0B", /* 12 */ "\x0C", /* 13 */ "\x0D", /* 14 */ "\x0E",/* 15 */
563 "\x0F", /* 16 */ "\x10", /* 17 */ "\x11", /* 18 */ "\x12", /* 19 */ "\x13",/* 20 */
564 "\x14", /* 21 */ "\x15", /* 22 */ "\x16", /* 23 */ "\x17", /* 24 */ "\x18",/* 25 */
565 "\x19", /* 26 */ "\x1A", /* 27 */ "\x1B", /* 28 */ "\x1C", /* 29 */ "\x1D",/* 30 */
566 "\x1E", /* 31 */ "\x1F", /* 32 */ "\x20", /* 33 */ "\x21", /* 34 */ "\x22",/* 35 */
567 "\x23", /* 36 */ "\x24", /* 37 */ "\x25", /* 38 */ "\x26", /* 39 */ "\x27",/* 40 */
568 "\x28", /* 41 */ "\x29", /* 42 */ "\x2A", /* 43 */ "\x2B", /* 44 */ "\x2C",/* 45 */
569 "\x2D", /* 46 */ "\x2E", /* 47 */ "\x2F", /* 48 */ "\x30", /* 49 */ "\x31",/* 50 */
570 "\x32", /* 51 */ "\x33", /* 52 */ "\x34", /* 53 */ "\x35", /* 54 */ "\x36",/* 55 */
571 "\x37", /* 56 */ "\x38", /* 57 */ "\x39", /* 58 */ "\x3A", /* 59 */ "\x3B",/* 60 */
572 "\x3C", /* 61 */ "\x3D", /* 62 */ "\x3E", /* 63 */ "\x3F", /* 64 */ "\x40",/* 65 */
573 "\x41", /* 66 */ "\x42", /* 67 */ "\x43", /* 68 */ "\x44", /* 69 */ "\x45",/* 70 */
574 "\x46", /* 71 */ "\x47", /* 72 */ "\x48", /* 73 */ "\x49", /* 74 */ "\x4A",/* 75 */
575 "\x4B", /* 76 */ "\x4C", /* 77 */ "\x4D", /* 78 */ "\x4E", /* 79 */ "\x4F",/* 80 */
576 "\x50", /* 81 */ "\x51", /* 82 */ "\x52", /* 83 */ "\x53", /* 84 */ "\x54",/* 85 */
577 "\x55", /* 86 */ "\x56", /* 87 */ "\x57", /* 88 */ "\x58", /* 89 */ "\x59",/* 90 */
578 "\x5A", /* 91 */ "\x5B", /* 92 */ "\x5C", /* 93 */ "\x5D", /* 94 */ "\x5E",/* 95 */
579 "\x5F", /* 96 */ "\x60", /* 97 */ "\x61", /* 98 */ "\x62", /* 99 */ "\x63",/* 100 */
580 "\x64", /* 101 */ "\x65", /* 102 */ "\x66", /* 103 */ "\x67", /* 104 */ "\x68",/* 105 */
581 "\x69", /* 106 */ "\x6A", /* 107 */ "\x6B", /* 108 */ "\x6C", /* 109 */ "\x6D",/* 110 */
582 "\x6E", /* 111 */ "\x6F", /* 112 */ "\x70", /* 113 */ "\x71", /* 114 */ "\x72",/* 115 */
583 "\x73", /* 116 */ "\x74", /* 117 */ "\x75", /* 118 */ "\x76", /* 119 */ "\x77",/* 120 */
584 "\x78", /* 121 */ "\x79", /* 122 */ "\x7A", /* 123 */ "\x7B", /* 124 */ "\x7C",/* 125 */
585 "\x7D", /* 126 */ "\x7E", /* 127 */ "\x7F", /* 128 */ "\xD0\x82", /* 129 */ "\xD0\x83",
586 /* 130 */
587 "\xE2\x80\x9A", /* 131 */ "\xD1\x93", /* 132 */ "\xE2\x80\x9E", /* 133 */ "\xE2\x80\xA6", /* 134 */ "\xE2\x80\xA0", /* 135 */ "\xE2\x80\xA1",
588 /* 136 */
589 "\xE2\x82\xAC", /* 137 */ "\xE2\x80\xB0", /* 138 */ "\xD0\x89", /* 139 */ "\xE2\x80\xB9", /* 140 */ "\xD0\x8A", /* 141 */ "\xD0\x8C",
590 /* 142 */
591 "\xD0\x8B", /* 143 */ "\xD0\x8F", /* 144 */ "\xD1\x92", /* 145 */ "\xE2\x80\x98", /* 146 */ "\xE2\x80\x99", /* 147 */ "\xE2\x80\x9C",
592 /* 148 */
593 "\xE2\x80\x9D", /* 149 */ "\xE2\x80\xA2", /* 150 */ "\xE2\x80\x93", /* 151 */ "\xE2\x80\x94", /* 152 */ "\xC2\x98", /* 153 */ "\xE2\x84\xA2",
594 /* 154 */
595 "\xD1\x99", /* 155 */ "\xE2\x80\xBA", /* 156 */ "\xD1\x9A", /* 157 */ "\xD1\x9C", /* 158 */ "\xD1\x9B", /* 159 */ "\xD1\x9F",
596 /* 160 */
597 "\xC2\xA0", /* 161 */ "\xD0\x8E", /* 162 */ "\xD1\x9E", /* 163 */ "\xD0\x88", /* 164 */ "\xC2\xA4", /* 165 */ "\xD2\x90",
598 /* 166 */
599 "\xC2\xA6", /* 167 */ "\xC2\xA7", /* 168 */ "\xD0\x81", /* 169 */ "\xC2\xA9", /* 170 */ "\xD0\x84", /* 171 */ "\xC2\xAB",
600 /* 172 */
601 "\xC2\xAC", /* 173 */ "\xC2\xAD", /* 174 */ "\xC2\xAE", /* 175 */ "\xD0\x87", /* 176 */ "\xC2\xB0", /* 177 */ "\xC2\xB1",
602 /* 178 */
603 "\xD0\x86", /* 179 */ "\xD1\x96", /* 180 */ "\xD2\x91", /* 181 */ "\xC2\xB5", /* 182 */ "\xC2\xB6", /* 183 */ "\xC2\xB7",
604 /* 184 */
605 "\xD1\x91", /* 185 */ "\xE2\x84\x96", /* 186 */ "\xD1\x94", /* 187 */ "\xC2\xBB", /* 188 */ "\xD1\x98", /* 189 */ "\xD0\x85",
606 /* 190 */
607 "\xD1\x95", /* 191 */ "\xD1\x97", /* 192 */ "\xD0\x90", /* 193 */ "\xD0\x91",/* 194 */
608 "\xD0\x92", /* 195 */ "\xD0\x93", /* 196 */ "\xD0\x94", /* 197 */ "\xD0\x95",
609 /* 198 */
610 "\xD0\x96", /* 199 */ "\xD0\x97", /* 200 */ "\xD0\x98", /* 201 */ "\xD0\x99",/* 202 */
611 "\xD0\x9A", /* 203 */ "\xD0\x9B", /* 204 */ "\xD0\x9C", /* 205 */ "\xD0\x9D",
612 /* 206 */
613 "\xD0\x9E", /* 207 */ "\xD0\x9F", /* 208 */ "\xD0\xA0", /* 209 */ "\xD0\xA1",/* 210 */
614 "\xD0\xA2", /* 211 */ "\xD0\xA3", /* 212 */ "\xD0\xA4", /* 213 */ "\xD0\xA5",
615 /* 214 */
616 "\xD0\xA6", /* 215 */ "\xD0\xA7", /* 216 */ "\xD0\xA8", /* 217 */ "\xD0\xA9",/* 218 */
617 "\xD0\xAA", /* 219 */ "\xD0\xAB", /* 220 */ "\xD0\xAC", /* 221 */ "\xD0\xAD",
618 /* 222 */
619 "\xD0\xAE", /* 223 */ "\xD0\xAF", /* 224 */ "\xD0\xB0", /* 225 */ "\xD0\xB1",/* 226 */
620 "\xD0\xB2", /* 227 */ "\xD0\xB3", /* 228 */ "\xD0\xB4", /* 229 */ "\xD0\xB5",
621 /* 230 */
622 "\xD0\xB6", /* 231 */ "\xD0\xB7", /* 232 */ "\xD0\xB8", /* 233 */ "\xD0\xB9",/* 234 */
623 "\xD0\xBA", /* 235 */ "\xD0\xBB", /* 236 */ "\xD0\xBC", /* 237 */ "\xD0\xBD",
624 /* 238 */
625 "\xD0\xBE", /* 239 */ "\xD0\xBF", /* 240 */ "\xD1\x80", /* 241 */ "\xD1\x81",/* 242 */
626 "\xD1\x82", /* 243 */ "\xD1\x83", /* 244 */ "\xD1\x84", /* 245 */ "\xD1\x85",
627 /* 246 */
628 "\xD1\x86", /* 247 */ "\xD1\x87", /* 248 */ "\xD1\x88", /* 249 */ "\xD1\x89",/* 250 */
629 "\xD1\x8A", /* 251 */ "\xD1\x8B", /* 252 */ "\xD1\x8C", /* 253 */ "\xD1\x8D",
630 /* 254 */
631 "\xD1\x8E", /* 255 */ "\xD1\x8F"
632 ];
633
634 private immutable int[sByte] mm1251= [/* 0 */
635 tBad, /* 1 */ tBad, /* 2 */ tBad, /* 3 */ tBad, /* 4 */ tBad, /* 5 */ tBad, /* 6 */ tBad, /* 7 */ tBad, /* 8 */ tBad,
636 /* 9 */
637 tBad, /* 10 */ tBad, /* 11 */ tBad, /* 12 */ tBad, /* 13 */ tBad, /* 14 */ tBad, /* 15 */ tBad, /* 16 */ tBad, /* 17 */ tBad,
638 /* 18 */
639 tBad, /* 19 */ tBad, /* 20 */ tBad, /* 21 */ tBad, /* 22 */ tBad, /* 23 */ tBad, /* 24 */ tBad, /* 25 */ tBad, /* 26 */ tBad,
640 /* 27 */
641 tBad, /* 28 */ tBad, /* 29 */ tBad, /* 30 */ tBad, /* 31 */ tBad, /* 32 */ tBad, /* 33 */ tPrint, /* 34 */ tPrint, /* 35 */ tPrint,
642 /* 36 */
643 tPrint, /* 37 */ tPrint, /* 38 */ tPrint, /* 39 */ tPrint, /* 40 */ tPrint, /* 41 */ tPrint, /* 42 */ tPrint, /* 43 */ tPrint, /* 44 */ tPrint,
644 /* 45 */
645 tPrint, /* 46 */ tPrint, /* 47 */ tPrint, /* 48 */ tPrint + tDigit, /* 49 */ tPrint + tDigit, /* 50 */ tPrint + tDigit, /* 51 */ tPrint + tDigit,
646 /* 52 */
647 tPrint + tDigit, /* 53 */ tPrint + tDigit, /* 54 */ tPrint + tDigit, /* 55 */ tPrint + tDigit,
648 /* 56 */
649 tPrint + tDigit, /* 57 */ tPrint + tDigit, /* 58 */ tPrint, /* 59 */ tPrint, /* 60 */ tPrint, /* 61 */ tPrint,
650 /* 62 */
651 tPrint, /* 63 */ tPrint, /* 64 */ tPrint,/* 65 */
652 tPrint + tEu, /* 66 */ tPrint + tEu, /* 67 */ tPrint + tEu, /* 68 */ tPrint + tEu, /* 69 */ tPrint + tEu, /* 70 */ tPrint + tEu,
653 /* 71 */
654 tPrint + tEu, /* 72 */ tPrint + tEu, /* 73 */ tPrint + tEu, /* 74 */ tPrint + tEu, /* 75 */ tPrint + tEu, /* 76 */ tPrint + tEu,
655 /* 77 */
656 tPrint + tEu, /* 78 */ tPrint + tEu, /* 79 */ tPrint + tEu, /* 80 */ tPrint + tEu, /* 81 */ tPrint + tEu, /* 82 */ tPrint + tEu,
657 /* 83 */
658 tPrint + tEu, /* 84 */ tPrint + tEu, /* 85 */ tPrint + tEu, /* 86 */ tPrint + tEu, /* 87 */ tPrint + tEu, /* 88 */ tPrint + tEu,
659 /* 89 */
660 tPrint + tEu, /* 90 */ tPrint + tEu,/* 91 */
661 tPrint, /* 92 */ tPrint, /* 93 */ tPrint, /* 94 */ tPrint, /* 95 */ tPrint,
662 /* 96 */
663 tPrint,/* 97 */
664 tPrint + tEl, /* 98 */ tPrint + tEl, /* 99 */ tPrint + tEl, /* 100 */ tPrint + tEl, /* 101 */ tPrint + tEl, /* 102 */ tPrint + tEl,
665 /* 103 */
666 tPrint + tEl, /* 104 */ tPrint + tEl, /* 105 */ tPrint + tEl, /* 106 */ tPrint + tEl, /* 107 */ tPrint + tEl, /* 108 */ tPrint + tEl,
667 /* 109 */
668 tPrint + tEl, /* 110 */ tPrint + tEl, /* 111 */ tPrint + tEl, /* 112 */ tPrint + tEl, /* 113 */ tPrint + tEl, /* 114 */ tPrint + tEl,
669 /* 115 */
670 tPrint + tEl, /* 116 */ tPrint + tEl, /* 117 */ tPrint + tEl, /* 118 */ tPrint + tEl, /* 119 */ tPrint + tEl, /* 120 */ tPrint + tEl,
671 /* 121 */
672 tPrint + tEl, /* 122 */ tPrint + tEl, /* 123 */ tPrint, /* 124 */ tPrint, /* 125 */ tPrint, /* 126 */ tPrint, /* 127 */ tPrint, /* 128 */ tPrint,
673 /* 129 */
674 tPrint,/* 130 */
675 tPrint, /* 131 */ tPrint, /* 132 */ tPrint, /* 133 */ tPrint, /* 134 */ tPrint, /* 135 */ tPrint, /* 136 */ tPrint, /* 137 */ tPrint,/* 138 */
676 tPrint, /* 139 */ tPrint, /* 140 */ tPrint, /* 141 */ tPrint, /* 142 */ tPrint, /* 143 */ tPrint, /* 144 */ tPrint, /* 145 */ tPrint,/* 146 */
677 tPrint, /* 147 */ tPrint, /* 148 */ tPrint, /* 149 */ tPrint, /* 150 */ tPrint, /* 151 */ tPrint, /* 152 */ tPrint, /* 153 */ tPrint,/* 154 */
678 tPrint, /* 155 */ tPrint, /* 156 */ tPrint, /* 157 */ tPrint, /* 158 */ tPrint, /* 159 */ tPrint, /* 160 */ tPrint, /* 161 */ tPrint,/* 162 */
679 tPrint, /* 163 */ tPrint, /* 164 */ tPrint, /* 165 */ tPrint, /* 166 */ tPrint, /* 167 */ tPrint, /* 168 */ tPrint + tRu, /* 169 */ tPrint,
680 /* 170 */
681 tPrint, /* 171 */ tPrint, /* 172 */ tPrint, /* 173 */ tPrint, /* 174 */ tPrint, /* 175 */ tPrint, /* 176 */ tPrint, /* 177 */ tPrint,/* 178 */
682 tPrint, /* 179 */ tPrint, /* 180 */ tPrint, /* 181 */ tPrint, /* 182 */ tPrint, /* 183 */ tPrint, /* 184 */ tPrint + tRl, /* 185 */ tPrint,
683 /* 186 */
684 tPrint, /* 187 */ tPrint, /* 188 */ tPrint, /* 189 */ tPrint, /* 190 */ tPrint, /* 191 */ tPrint, /* 192 */ tPrint + tRu,
685 /* 193 */
686 tPrint + tRu, /* 194 */ tPrint + tRu, /* 195 */ tPrint + tRu, /* 196 */ tPrint + tRu, /* 197 */ tPrint + tRu, /* 198 */ tPrint + tRu,
687 /* 199 */
688 tPrint + tRu, /* 200 */ tPrint + tRu, /* 201 */ tPrint + tRu, /* 202 */ tPrint + tRu, /* 203 */ tPrint + tRu, /* 204 */ tPrint + tRu,
689 /* 205 */
690 tPrint + tRu, /* 206 */ tPrint + tRu, /* 207 */ tPrint + tRu, /* 208 */ tPrint + tRu, /* 209 */ tPrint + tRu, /* 210 */ tPrint + tRu,
691 /* 211 */
692 tPrint + tRu, /* 212 */ tPrint + tRu, /* 213 */ tPrint + tRu, /* 214 */ tPrint + tRu, /* 215 */ tPrint + tRu, /* 216 */ tPrint + tRu,
693 /* 217 */
694 tPrint + tRu, /* 218 */ tPrint + tRu, /* 219 */ tPrint + tRu, /* 220 */ tPrint + tRu, /* 221 */ tPrint + tRu, /* 222 */ tPrint + tRu,
695 /* 223 */
696 tPrint + tRu, /* 224 */ tPrint + tRl, /* 225 */ tPrint + tRl, /* 226 */ tPrint + tRl, /* 227 */ tPrint + tRl, /* 228 */ tPrint + tRl,
697 /* 229 */
698 tPrint + tRl, /* 230 */ tPrint + tRl, /* 231 */ tPrint + tRl, /* 232 */ tPrint + tRl, /* 233 */ tPrint + tRl, /* 234 */ tPrint + tRl,
699 /* 235 */
700 tPrint + tRl, /* 236 */ tPrint + tRl, /* 237 */ tPrint + tRl, /* 238 */ tPrint + tRl, /* 239 */ tPrint + tRl, /* 240 */ tPrint + tRl,
701 /* 241 */
702 tPrint + tRl, /* 242 */ tPrint + tRl, /* 243 */ tPrint + tRl, /* 244 */ tPrint + tRl, /* 245 */ tPrint + tRl, /* 246 */ tPrint + tRl,
703 /* 247 */
704 tPrint + tRl, /* 248 */ tPrint + tRl, /* 249 */ tPrint + tRl, /* 250 */ tPrint + tRl, /* 251 */ tPrint + tRl, /* 252 */ tPrint + tRl,
705 /* 253 */
706 tPrint + tRl, /* 254 */ tPrint + tRl, /* 255 */ tPrint + tRl];
707
708 // char mm1251u[sByte];
709 private immutable uppercase1251R = "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF"; /// А..Я
710 private immutable lowercase1251R = "\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF"; /// А..Я
711 private immutable _1251_866 = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x18\x19\x1A\x1B......\x20!\x22#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~.+++++++++++++++++++++++++++++++++++++++1\xF0345+++++++++++1\xF1\xFC++++++\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF";
712 private immutable char[62] tbl_xD1 = [
713 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, 0,184,144,131,186,190,
714 179,191,188,154,156,158,157, 0,162,159, 0, 0,210,211,212,213,214,215,216,217,218,219,
715 220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237
716 ];
717 private immutable char[63] tbl_xD0 = [
718 168,128,129,170,189,178,175,163,138,140,142,141, 0,161,143,192,193,194,195,196,197,198,
719 199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,
720 221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239
721 ];
722 private immutable char[40] tbl_x80 = [
723 150,151, 0, 0, 0,145,146,130, 0,147,148,132, 0,134,135,149, 0, 0, 0,133, 0, 0,
724 0, 0, 0, 0, 0, 0, 0,137, 0, 0, 0, 0, 0, 0, 0, 0,139,155
725 ];
726 private immutable char[36] tbl_xC2 = [
727 152, 0, 0, 0, 0, 0, 0, 0,160, 0, 0, 0,164, 0,166,167, 0,169, 0,171,172,173,
728 174, 0,176,177, 0, 0, 0,181,182,183, 0, 0, 0,187
729 ];
730
731 bool isAtr1251(char c, int atr) {
732 return (mm1251[c] & atr) != 0;
733 }