Преобразование сложных числительных в числа

VladimirR

Client
Регистрация
10.07.2019
Сообщения
7
Благодарностей
2
Баллы
3
Маюсь с одним вопросом: как преобразовать сложные числительные в тексте в их цифровые значения, например: "один миллион двести тридцать четыре тысячи пятьсот шестьдесят семь пингвинов" в "1234567 пингвинов".
Находил много близких тем, например эту, но решения так и не нашёл - многое уже удалено.
Может кто-то хотя бы находил решение этого вопроса через API? Есть близкие ресурсы, позволяющие написать цифры буквами (не совсем то - т.к. здесь добавляются рубли и копейки и теряется остальной текст), но мне нужно наоборот: буквы => цифры.
 

Sergodjan

Administrator
Команда форума
Регистрация
05.09.2012
Сообщения
21 324
Благодарностей
9 474
Баллы
113
Маюсь с одним вопросом: как преобразовать сложные числительные в тексте в их цифровые значения, например: "один миллион двести тридцать четыре тысячи пятьсот шестьдесят семь пингвинов" в "1234567 пингвинов".
Находил много близких тем, например эту, но решения так и не нашёл - многое уже удалено.
Может кто-то хотя бы находил решение этого вопроса через API? Есть близкие ресурсы, позволяющие написать цифры буквами (не совсем то - т.к. здесь добавляются рубли и копейки и теряется остальной текст), но мне нужно наоборот: буквы => цифры.
ИИ не подойдет?

133375
 

VladimirR

Client
Регистрация
10.07.2019
Сообщения
7
Благодарностей
2
Баллы
3
Думал в сторону ИИ, но немного с другой стороны: попросил ИИ написать код на C# для решения этой задачи, вот что получилось:

C#:
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

public class ZennoPosterRussianNumberConverter
{
    private static readonly Dictionary<string, long> NumberWords = new Dictionary<string, long>
    {
        {"ноль", 0}, {"один", 1}, {"одна", 1}, {"одно", 1}, {"два", 2}, {"две", 2},
        {"три", 3}, {"четыре", 4}, {"пять", 5}, {"шесть", 6}, {"семь", 7},
        {"восемь", 8}, {"девять", 9}, {"десять", 10}, {"одиннадцать", 11},
        {"двенадцать", 12}, {"тринадцать", 13}, {"четырнадцать", 14},
        {"пятнадцать", 15}, {"шестнадцать", 16}, {"семнадцать", 17},
        {"восемнадцать", 18}, {"девятнадцать", 19}, {"двадцать", 20},
        {"тридцать", 30}, {"сорок", 40}, {"пятьдесят", 50}, {"шестьдесят", 60},
        {"семьдесят", 70}, {"восемьдесят", 80}, {"девяносто", 90},
        {"сто", 100}, {"двести", 200}, {"триста", 300}, {"четыреста", 400},
        {"пятьсот", 500}, {"шестьсот", 600}, {"семьсот", 700}, {"восемьсот", 800},
        {"девятьсот", 900}, {"тысяча", 1000}, {"тысячи", 1000}, {"тысяч", 1000},
        {"миллион", 1000000}, {"миллиона", 1000000}, {"миллионов", 1000000},
        {"миллиард", 1000000000}, {"миллиарда", 1000000000}, {"миллиардов", 1000000000}
    };

    public static string ConvertWordsToNumbers(string text, IZennoPosterProjectModel project)
    {
        try
        {
            if (string.IsNullOrEmpty(text))
                return text;

            // Регулярное выражение для русских числовых слов
            string pattern = @"\b(ноль|один|одна|одно|два|две|три|четыре|пять|шесть|семь|восемь|девять|десять|одиннадцать|двенадцать|тринадцать|четырнадцать|пятнадцать|шестнадцать|семнадцать|восемнадцать|девятнадцать|двадцать|тридцать|сорок|пятьдесят|шестьдесят|семьдесят|восемьдесят|девяносто|сто|двести|триста|четыреста|пятьсот|шестьсот|семьсот|восемьсот|девятьсот|тысяча|тысячи|тысяч|миллион|миллиона|миллионов|миллиард|миллиарда|миллиардов)\b";
            string[] words = Regex.Split(text.ToLower(), pattern, RegexOptions.IgnoreCase);
            string result = text;
            string currentNumberWords = "";
            bool isProcessingNumber = false;

            string ProcessNumberWords(string numberWords)
            {
                if (string.IsNullOrEmpty(numberWords))
                    return "";

                string[] parts = numberWords.Trim().Split();
                long total = 0, current = 0;

                foreach (string word in parts)
                {
                    if (NumberWords.TryGetValue(word, out long value))
                    {
                        if (value >= 1000) // тысяча, миллион, миллиард
                        {
                            current = current == 0 ? 1 : current;
                            total += current * value;
                            current = 0;
                        }
                        else if (value >= 100) // сотни
                        {
                            current = current == 0 ? value : current + value;
                        }
                        else // числа от 0 до 90
                        {
                            current += value;
                        }
                    }
                }

                total += current;
                return total.ToString();
            }

            for (int i = 0; i < words.Length; i++)
            {
                if (Regex.IsMatch(words[i], pattern, RegexOptions.IgnoreCase))
                {
                    currentNumberWords += words[i] + " ";
                    isProcessingNumber = true;
                }
                else
                {
                    if (isProcessingNumber)
                    {
                        string numberString = ProcessNumberWords(currentNumberWords);
                        string originalNumberWords = text.Substring(result.Length - currentNumberWords.Length, currentNumberWords.Length).Trim();
                        result = result.Substring(0, result.Length - currentNumberWords.Length) + numberString;
                        currentNumberWords = "";
                        isProcessingNumber = false;
                    }
                    result = result.Substring(0, result.Length - words[i].Length) + words[i];
                }
            }

            if (isProcessingNumber)
            {
                string numberString = ProcessNumberWords(currentNumberWords);
                result = result.Substring(0, result.Length - currentNumberWords.Length) + numberString;
            }

            return result;
        }
        catch (Exception ex)
        {
            project.SendErrorToLog($"Error in ConvertWordsToNumbers: {ex.Message}", false);
            return text; // Возвращаем исходный текст в случае ошибки
        }
    }
}
Должен признаться, что сами мы не местные, халат старый и програмировать на C# мы умеем только на уровне copy/paste :ap:
Может кто-то сможет скорректировать данный код, чтобы он работал в Zennoposter, и/или объяснить как настроить Zennoposter чтобы случилось чудо и Франкенштейн ожил?
 
  • Спасибо
Реакции: Sergodjan

Billy_One

Новичок
Регистрация
20.05.2025
Сообщения
1
Благодарностей
0
Баллы
1
Кто то слишком заморачивается кгда есть готовое решение:
int n = Convert.ToInt32(project.Variables["number"].Value);
return n;
 

DV_

Client
Регистрация
21.08.2020
Сообщения
91
Благодарностей
23
Баллы
8

Sherminator

Client
Регистрация
10.09.2021
Сообщения
1 485
Благодарностей
860
Баллы
113
Думал в сторону ИИ, но немного с другой стороны: попросил ИИ написать код на C# для решения этой задачи, вот что получилось:

C#:
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

public class ZennoPosterRussianNumberConverter
{
    private static readonly Dictionary<string, long> NumberWords = new Dictionary<string, long>
    {
        {"ноль", 0}, {"один", 1}, {"одна", 1}, {"одно", 1}, {"два", 2}, {"две", 2},
        {"три", 3}, {"четыре", 4}, {"пять", 5}, {"шесть", 6}, {"семь", 7},
        {"восемь", 8}, {"девять", 9}, {"десять", 10}, {"одиннадцать", 11},
        {"двенадцать", 12}, {"тринадцать", 13}, {"четырнадцать", 14},
        {"пятнадцать", 15}, {"шестнадцать", 16}, {"семнадцать", 17},
        {"восемнадцать", 18}, {"девятнадцать", 19}, {"двадцать", 20},
        {"тридцать", 30}, {"сорок", 40}, {"пятьдесят", 50}, {"шестьдесят", 60},
        {"семьдесят", 70}, {"восемьдесят", 80}, {"девяносто", 90},
        {"сто", 100}, {"двести", 200}, {"триста", 300}, {"четыреста", 400},
        {"пятьсот", 500}, {"шестьсот", 600}, {"семьсот", 700}, {"восемьсот", 800},
        {"девятьсот", 900}, {"тысяча", 1000}, {"тысячи", 1000}, {"тысяч", 1000},
        {"миллион", 1000000}, {"миллиона", 1000000}, {"миллионов", 1000000},
        {"миллиард", 1000000000}, {"миллиарда", 1000000000}, {"миллиардов", 1000000000}
    };

    public static string ConvertWordsToNumbers(string text, IZennoPosterProjectModel project)
    {
        try
        {
            if (string.IsNullOrEmpty(text))
                return text;

            // Регулярное выражение для русских числовых слов
            string pattern = @"\b(ноль|один|одна|одно|два|две|три|четыре|пять|шесть|семь|восемь|девять|десять|одиннадцать|двенадцать|тринадцать|четырнадцать|пятнадцать|шестнадцать|семнадцать|восемнадцать|девятнадцать|двадцать|тридцать|сорок|пятьдесят|шестьдесят|семьдесят|восемьдесят|девяносто|сто|двести|триста|четыреста|пятьсот|шестьсот|семьсот|восемьсот|девятьсот|тысяча|тысячи|тысяч|миллион|миллиона|миллионов|миллиард|миллиарда|миллиардов)\b";
            string[] words = Regex.Split(text.ToLower(), pattern, RegexOptions.IgnoreCase);
            string result = text;
            string currentNumberWords = "";
            bool isProcessingNumber = false;

            string ProcessNumberWords(string numberWords)
            {
                if (string.IsNullOrEmpty(numberWords))
                    return "";

                string[] parts = numberWords.Trim().Split();
                long total = 0, current = 0;

                foreach (string word in parts)
                {
                    if (NumberWords.TryGetValue(word, out long value))
                    {
                        if (value >= 1000) // тысяча, миллион, миллиард
                        {
                            current = current == 0 ? 1 : current;
                            total += current * value;
                            current = 0;
                        }
                        else if (value >= 100) // сотни
                        {
                            current = current == 0 ? value : current + value;
                        }
                        else // числа от 0 до 90
                        {
                            current += value;
                        }
                    }
                }

                total += current;
                return total.ToString();
            }

            for (int i = 0; i < words.Length; i++)
            {
                if (Regex.IsMatch(words[i], pattern, RegexOptions.IgnoreCase))
                {
                    currentNumberWords += words[i] + " ";
                    isProcessingNumber = true;
                }
                else
                {
                    if (isProcessingNumber)
                    {
                        string numberString = ProcessNumberWords(currentNumberWords);
                        string originalNumberWords = text.Substring(result.Length - currentNumberWords.Length, currentNumberWords.Length).Trim();
                        result = result.Substring(0, result.Length - currentNumberWords.Length) + numberString;
                        currentNumberWords = "";
                        isProcessingNumber = false;
                    }
                    result = result.Substring(0, result.Length - words[i].Length) + words[i];
                }
            }

            if (isProcessingNumber)
            {
                string numberString = ProcessNumberWords(currentNumberWords);
                result = result.Substring(0, result.Length - currentNumberWords.Length) + numberString;
            }

            return result;
        }
        catch (Exception ex)
        {
            project.SendErrorToLog($"Error in ConvertWordsToNumbers: {ex.Message}", false);
            return text; // Возвращаем исходный текст в случае ошибки
        }
    }
}
Должен признаться, что сами мы не местные, халат старый и програмировать на C# мы умеем только на уровне copy/paste :ap:
Может кто-то сможет скорректировать данный код, чтобы он работал в Zennoposter, и/или объяснить как настроить Zennoposter чтобы случилось чудо и Франкенштейн ожил?
Ну я адаптировал, чекнул, говно код, криво работает
 

Sherminator

Client
Регистрация
10.09.2021
Сообщения
1 485
Благодарностей
860
Баллы
113
Вот, в c# кубик запихни, текст помещать в переменную TextNumber, её создать надо

133415



C#:
Dictionary<string, long> NumberWords = new Dictionary<string, long>
{
    {"ноль", 0}, {"один", 1}, {"одна", 1}, {"одно", 1}, {"два", 2}, {"две", 2},
    {"три", 3}, {"четыре", 4}, {"пять", 5}, {"шесть", 6}, {"семь", 7},
    {"восемь", 8}, {"девять", 9}, {"десять", 10}, {"одиннадцать", 11},
    {"двенадцать", 12}, {"тринадцать", 13}, {"четырнадцать", 14},
    {"пятнадцать", 15}, {"шестнадцать", 16}, {"семнадцать", 17},
    {"восемнадцать", 18}, {"девятнадцать", 19}, {"двадцать", 20},
    {"тридцать", 30}, {"сорок", 40}, {"пятьдесят", 50}, {"шестьдесят", 60},
    {"семьдесят", 70}, {"восемьдесят", 80}, {"девяносто", 90},
    {"сто", 100}, {"двести", 200}, {"триста", 300}, {"четыреста", 400},
    {"пятьсот", 500}, {"шестьсот", 600}, {"семьсот", 700}, {"восемьсот", 800},
    {"девятьсот", 900}, {"тысяча", 1000}, {"тысячи", 1000}, {"тысяч", 1000},
    {"миллион", 1000000}, {"миллиона", 1000000}, {"миллионов", 1000000},
    {"миллиард", 1000000000}, {"миллиарда", 1000000000}, {"миллиардов", 1000000000}
};

long ProcessWords(string input)
{
    string[] tokens = input.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
    long total = 0, current = 0;
    foreach (var token in tokens)
    {
        if (!NumberWords.TryGetValue(token, out long val)) continue;

        if (val >= 1000)
        {
            current = current == 0 ? 1 : current;
            total += current * val;
            current = 0;
        }
        else
        {
            current += val;
        }
    }
    return total + current;
}

string ReplaceWordsWithNumbers(string input)
{
    if (string.IsNullOrWhiteSpace(input)) return input;

    string pattern = @"((?:\b(?:ноль|один|одна|одно|два|две|три|четыре|пять|шесть|семь|восемь|девять|десять|одиннадцать|двенадцать|тринадцать|четырнадцать|пятнадцать|шестнадцать|семнадцать|восемнадцать|девятнадцать|двадцать|тридцать|сорок|пятьдесят|шестьдесят|семьдесят|восемьдесят|девяносто|сто|двести|триста|четыреста|пятьсот|шестьсот|семьсот|восемьсот|девятьсот|тысяча|тысячи|тысяч|миллион|миллиона|миллионов|миллиард|миллиарда|миллиардов)\b[\s]*)+)";
    return Regex.Replace(input.ToLower(), pattern, m =>
{
    string group = m.Groups[1].Value.Trim();
    long number = ProcessWords(group);
    string nextChar = input.Length > m.Index + m.Length ? input[m.Index + m.Length].ToString() : "";
    bool needSpace = !string.IsNullOrEmpty(nextChar) && char.IsLetter(nextChar[0]);
    return number.ToString() + (needSpace ? " " : "");
}, RegexOptions.IgnoreCase);
}

string text = project.Variables["TextNumber"].Value;
try
{
    return ReplaceWordsWithNumbers(text);
}
catch (Exception ex)
{
    project.SendErrorToLog($"Ошибка в ReplaceWordsWithNumbers: {ex.Message}", false);
    return text;
}
 
  • Спасибо
Реакции: Sergodjan

Sergodjan

Administrator
Команда форума
Регистрация
05.09.2012
Сообщения
21 324
Благодарностей
9 474
Баллы
113

Sherminator

Client
Регистрация
10.09.2021
Сообщения
1 485
Благодарностей
860
Баллы
113
  • Спасибо
Реакции: Sergodjan

Кто просматривает тему: (Всего: 1, Пользователи: 0, Гости: 1)