Upload ChatIPC.cpp
Browse files- ChatIPC.cpp +114 -51
ChatIPC.cpp
CHANGED
|
@@ -495,63 +495,105 @@ static const char* const scales[] = {"", "thousand", "million", "billion", "tril
|
|
| 495 |
"quattuordecillion", "quindecillion", "sexdecillion", "septendecillion",
|
| 496 |
"octodecillion", "novemdecillion", "vigintillion", "googol"};
|
| 497 |
|
| 498 |
-
static std::vector<std::string> digit_to_words(const std::string&
|
| 499 |
std::vector<std::string> words;
|
| 500 |
-
if (
|
| 501 |
|
| 502 |
-
//
|
| 503 |
-
|
| 504 |
-
|
| 505 |
-
|
| 506 |
-
|
|
|
|
|
|
|
| 507 |
}
|
| 508 |
-
std::string num = s.substr(first_non_zero);
|
| 509 |
|
| 510 |
-
//
|
| 511 |
-
|
| 512 |
-
|
| 513 |
-
|
| 514 |
-
|
| 515 |
}
|
| 516 |
-
return words;
|
| 517 |
}
|
| 518 |
|
| 519 |
-
|
| 520 |
-
|
| 521 |
-
|
| 522 |
-
|
| 523 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 524 |
|
| 525 |
-
|
| 526 |
-
|
| 527 |
-
|
| 528 |
-
|
| 529 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 530 |
|
| 531 |
-
|
| 532 |
-
|
| 533 |
-
|
| 534 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 535 |
|
| 536 |
-
|
| 537 |
-
|
| 538 |
-
|
| 539 |
-
|
| 540 |
-
|
| 541 |
-
if (remainder % 10 > 0) {
|
| 542 |
-
chunk_words.push_back(ones[remainder % 10]);
|
| 543 |
}
|
|
|
|
| 544 |
}
|
| 545 |
}
|
|
|
|
|
|
|
| 546 |
|
| 547 |
-
|
| 548 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 549 |
}
|
| 550 |
-
|
| 551 |
-
words.insert(words.begin(), chunk_words.begin(), chunk_words.end());
|
| 552 |
}
|
| 553 |
-
scale_idx++;
|
| 554 |
}
|
|
|
|
| 555 |
return words;
|
| 556 |
}
|
| 557 |
|
|
@@ -565,10 +607,13 @@ static std::vector<std::string> tokenize_others(const std::string &s) {
|
|
| 565 |
return { lower_s };
|
| 566 |
}
|
| 567 |
|
| 568 |
-
//
|
| 569 |
-
|
| 570 |
-
return std::isdigit(c) != 0;
|
| 571 |
-
}
|
|
|
|
|
|
|
|
|
|
| 572 |
if (is_all_digits) {
|
| 573 |
return digit_to_words(s);
|
| 574 |
}
|
|
@@ -578,9 +623,15 @@ static std::vector<std::string> tokenize_others(const std::string &s) {
|
|
| 578 |
|
| 579 |
auto flush = [&]() {
|
| 580 |
if (!cur.empty()) {
|
| 581 |
-
// Check numbers inside mixed tokens (e.g. "
|
| 582 |
-
bool cur_all_digits = std::all_of(cur.begin(), cur.end(), [](unsigned char c) {
|
| 583 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 584 |
auto words = digit_to_words(cur);
|
| 585 |
out.insert(out.end(), words.begin(), words.end());
|
| 586 |
} else {
|
|
@@ -598,13 +649,25 @@ static std::vector<std::string> tokenize_others(const std::string &s) {
|
|
| 598 |
char ch = static_cast<char>(uc);
|
| 599 |
|
| 600 |
// Check for Operator/Symbol extraction
|
| 601 |
-
if (std::ispunct(uc) || (std::isprint(uc) && !std::isalnum(uc) && !std::isspace(uc))) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 602 |
std::string sym(1, ch);
|
| 603 |
|
| 604 |
-
// Check for double-character operators
|
| 605 |
if (i + 1 < s.size()) {
|
| 606 |
unsigned char nxt_uc = static_cast<unsigned char>(s[i+1]);
|
| 607 |
-
if (std::ispunct(nxt_uc) || (std::isprint(nxt_uc) && !std::isalnum(nxt_uc) && !std::isspace(nxt_uc))) {
|
|
|
|
| 608 |
if (check_dictionary(sym2)) {
|
| 609 |
out.push_back(sym2);
|
| 610 |
++i;
|
|
@@ -636,7 +699,7 @@ static std::vector<std::string> tokenize_others(const std::string &s) {
|
|
| 636 |
bool digit_boundary = false;
|
| 637 |
if (!cur.empty()) {
|
| 638 |
unsigned char prev = static_cast<unsigned char>(s[i - 1]);
|
| 639 |
-
bool prev_digit = std::isdigit(prev) != 0;
|
| 640 |
bool curr_digit = std::isdigit(uc) != 0;
|
| 641 |
if (prev_digit != curr_digit) {
|
| 642 |
digit_boundary = true;
|
|
|
|
| 495 |
"quattuordecillion", "quindecillion", "sexdecillion", "septendecillion",
|
| 496 |
"octodecillion", "novemdecillion", "vigintillion", "googol"};
|
| 497 |
|
| 498 |
+
static std::vector<std::string> digit_to_words(const std::string& input_s) {
|
| 499 |
std::vector<std::string> words;
|
| 500 |
+
if (input_s.empty()) return words;
|
| 501 |
|
| 502 |
+
// Split the number into integer and fractional parts
|
| 503 |
+
std::string int_part = input_s;
|
| 504 |
+
std::string frac_part = "";
|
| 505 |
+
size_t dot_pos = input_s.find('.');
|
| 506 |
+
if (dot_pos != std::string::npos) {
|
| 507 |
+
int_part = input_s.substr(0, dot_pos);
|
| 508 |
+
frac_part = input_s.substr(dot_pos + 1);
|
| 509 |
}
|
|
|
|
| 510 |
|
| 511 |
+
// Clean the integer part by removing commas
|
| 512 |
+
std::string s;
|
| 513 |
+
for (char c : int_part) {
|
| 514 |
+
if (std::isdigit(static_cast<unsigned char>(c))) {
|
| 515 |
+
s.push_back(c);
|
| 516 |
}
|
|
|
|
| 517 |
}
|
| 518 |
|
| 519 |
+
// Process the integer part
|
| 520 |
+
if (s.empty()) {
|
| 521 |
+
// If there are no integer digits, ensure there are fractional digits before parsing
|
| 522 |
+
bool has_frac_digits = false;
|
| 523 |
+
for (char c : frac_part) {
|
| 524 |
+
if (std::isdigit(static_cast<unsigned char>(c))) has_frac_digits = true;
|
| 525 |
+
}
|
| 526 |
+
if (!has_frac_digits) return words;
|
| 527 |
+
words.push_back("zero");
|
| 528 |
+
} else {
|
| 529 |
+
size_t first_non_zero = s.find_first_not_of('0');
|
| 530 |
+
if (first_non_zero == std::string::npos) {
|
| 531 |
+
words.push_back("zero");
|
| 532 |
+
} else {
|
| 533 |
+
std::string num = s.substr(first_non_zero);
|
| 534 |
|
| 535 |
+
// Fallback for extremely large numbers to prevent overflow
|
| 536 |
+
if (num.length() > 69) {
|
| 537 |
+
for (char c : num) {
|
| 538 |
+
words.push_back(ones[c - '0']);
|
| 539 |
+
}
|
| 540 |
+
} else {
|
| 541 |
+
int scale_idx = 0;
|
| 542 |
+
while (!num.empty()) {
|
| 543 |
+
int chunk_len = std::min<int>(3, num.length());
|
| 544 |
+
std::string chunk_str = num.substr(num.length() - chunk_len);
|
| 545 |
+
num = num.substr(0, num.length() - chunk_len);
|
| 546 |
+
|
| 547 |
+
int chunk = std::stoi(chunk_str);
|
| 548 |
+
if (chunk > 0) {
|
| 549 |
+
std::vector<std::string> chunk_words;
|
| 550 |
+
int h = chunk / 100;
|
| 551 |
+
int remainder = chunk % 100;
|
| 552 |
+
|
| 553 |
+
if (h > 0) {
|
| 554 |
+
chunk_words.push_back(ones[h]);
|
| 555 |
+
chunk_words.push_back("hundred");
|
| 556 |
+
}
|
| 557 |
|
| 558 |
+
if (remainder > 0) {
|
| 559 |
+
if (remainder < 20) {
|
| 560 |
+
chunk_words.push_back(ones[remainder]);
|
| 561 |
+
} else {
|
| 562 |
+
chunk_words.push_back(tens[remainder / 10]);
|
| 563 |
+
if (remainder % 10 > 0) {
|
| 564 |
+
chunk_words.push_back(ones[remainder % 10]);
|
| 565 |
+
}
|
| 566 |
+
}
|
| 567 |
+
}
|
| 568 |
|
| 569 |
+
if (scale_idx > 0 && scale_idx < static_cast<int>(sizeof(scales)/sizeof(scales[0]))) {
|
| 570 |
+
chunk_words.push_back(scales[scale_idx]);
|
| 571 |
+
}
|
| 572 |
+
|
| 573 |
+
words.insert(words.begin(), chunk_words.begin(), chunk_words.end());
|
|
|
|
|
|
|
| 574 |
}
|
| 575 |
+
scale_idx++;
|
| 576 |
}
|
| 577 |
}
|
| 578 |
+
}
|
| 579 |
+
}
|
| 580 |
|
| 581 |
+
// Process the fractional part
|
| 582 |
+
if (!frac_part.empty()) {
|
| 583 |
+
bool has_frac_digits = false;
|
| 584 |
+
for (char c : frac_part) {
|
| 585 |
+
if (std::isdigit(static_cast<unsigned char>(c))) has_frac_digits = true;
|
| 586 |
+
}
|
| 587 |
+
if (has_frac_digits) {
|
| 588 |
+
words.push_back("point");
|
| 589 |
+
for (char c : frac_part) {
|
| 590 |
+
if (std::isdigit(static_cast<unsigned char>(c))) {
|
| 591 |
+
words.push_back(ones[c - '0']);
|
| 592 |
+
}
|
| 593 |
}
|
|
|
|
|
|
|
| 594 |
}
|
|
|
|
| 595 |
}
|
| 596 |
+
|
| 597 |
return words;
|
| 598 |
}
|
| 599 |
|
|
|
|
| 607 |
return { lower_s };
|
| 608 |
}
|
| 609 |
|
| 610 |
+
// Check if the entire string is a formatted number (pure digits, commas, and dots)
|
| 611 |
+
auto is_num_char = [](unsigned char c) {
|
| 612 |
+
return std::isdigit(c) != 0 || c == ',' || c == '.';
|
| 613 |
+
};
|
| 614 |
+
bool is_all_digits = !s.empty() && std::all_of(s.begin(), s.end(), is_num_char) &&
|
| 615 |
+
std::any_of(s.begin(), s.end(), [](unsigned char c) { return std::isdigit(c) != 0; });
|
| 616 |
+
|
| 617 |
if (is_all_digits) {
|
| 618 |
return digit_to_words(s);
|
| 619 |
}
|
|
|
|
| 623 |
|
| 624 |
auto flush = [&]() {
|
| 625 |
if (!cur.empty()) {
|
| 626 |
+
// Check numbers inside mixed tokens (e.g. "word1,234.56")
|
| 627 |
+
bool cur_all_digits = std::all_of(cur.begin(), cur.end(), [](unsigned char c) {
|
| 628 |
+
return std::isdigit(c) != 0 || c == ',' || c == '.';
|
| 629 |
+
});
|
| 630 |
+
bool has_digits = std::any_of(cur.begin(), cur.end(), [](unsigned char c) {
|
| 631 |
+
return std::isdigit(c) != 0;
|
| 632 |
+
});
|
| 633 |
+
|
| 634 |
+
if (cur_all_digits && has_digits) {
|
| 635 |
auto words = digit_to_words(cur);
|
| 636 |
out.insert(out.end(), words.begin(), words.end());
|
| 637 |
} else {
|
|
|
|
| 649 |
char ch = static_cast<char>(uc);
|
| 650 |
|
| 651 |
// Check for Operator/Symbol extraction
|
| 652 |
+
if (std::ispunct(uc) || (std::isprint(uc) && !std::isalnum(uc) && !std::isspace(uc))) {
|
| 653 |
+
|
| 654 |
+
// Bypass regular punctuation extraction inside a formatted number
|
| 655 |
+
if ((ch == ',' || ch == '.') &&
|
| 656 |
+
!cur.empty() &&
|
| 657 |
+
(std::isdigit(static_cast<unsigned char>(cur.back())) != 0 || cur.back() == ',' || cur.back() == '.') &&
|
| 658 |
+
(i + 1 < s.size()) && std::isdigit(static_cast<unsigned char>(s[i+1])) != 0) {
|
| 659 |
+
cur.push_back(ch);
|
| 660 |
+
continue;
|
| 661 |
+
}
|
| 662 |
+
|
| 663 |
+
flush();
|
| 664 |
std::string sym(1, ch);
|
| 665 |
|
| 666 |
+
// Check for double-character operators
|
| 667 |
if (i + 1 < s.size()) {
|
| 668 |
unsigned char nxt_uc = static_cast<unsigned char>(s[i+1]);
|
| 669 |
+
if (std::ispunct(nxt_uc) || (std::isprint(nxt_uc) && !std::isalnum(nxt_uc) && !std::isspace(nxt_uc))) {
|
| 670 |
+
std::string sym2 = sym + static_cast<char>(nxt_uc);
|
| 671 |
if (check_dictionary(sym2)) {
|
| 672 |
out.push_back(sym2);
|
| 673 |
++i;
|
|
|
|
| 699 |
bool digit_boundary = false;
|
| 700 |
if (!cur.empty()) {
|
| 701 |
unsigned char prev = static_cast<unsigned char>(s[i - 1]);
|
| 702 |
+
bool prev_digit = (std::isdigit(prev) != 0) || prev == ',' || prev == '.';
|
| 703 |
bool curr_digit = std::isdigit(uc) != 0;
|
| 704 |
if (prev_digit != curr_digit) {
|
| 705 |
digit_boundary = true;
|