из буквенной записи числа в цифровую

function w2d(str){
  this.str = str;
  this.output = this.str.replace(/\sноль\s|\sнуль\s/gi, ' 0 ').replace(/один\s/gi, '1 ').replace(/два\s/gi, '2 ').replace(/три\s/gi, '3 ').replace(/четыре\s/gi, '4 ').replace(/пять\s/gi, '5 ').replace(/\sшесть\s/gi, ' 6 ').replace(/\sсемь\s/gi, ' 7 ').replace(/\sвосемь\s/gi, ' 8 ').replace(/\sдевять\s/gi, ' 9 ').replace(/\sдесять\s/gi, ' 10 ').replace(/\sодиннадцать\s/gi, ' 11 ').replace(/\sдвенадцать\s/gi, ' 12 ').replace(/\sтринадцать\s/gi, ' 13 ').replace(/\sчетырнадцать\s/gi, ' 14 ').replace(/\sпятнадцать\s/gi, ' 15 ').replace(/\sшестнадцать\s/gi, ' 16 ').replace(/\sсемнадцать\s/gi, ' 17 ').replace(/\sвосемнадцать\s/gi, ' 18 ').replace(/\sдевятнадцать\s/gi, ' 19 ').replace(/\sдвадцать\s/gi, ' 20 ').replace(/\sдвадцать один\s/gi, ' 21 ').replace(/\sдвадцать два\s/gi, ' 22 ').replace(/\sдвадцать три\s/gi, ' 23 ').replace(/\sдвадцать четыре\s/gi, ' 24 ').replace(/\sдвадцать\s/gi, ' 25 ');
  return this.output;
}

функцию ещё не доделал(хочу до 60 доделать), но уже есть проблемы допустим "двадцать один" преобразуется в "20 1", вообще хотел изначально с двадцати, чтобы было примерно так str.replace(/\sдвадцать (?<name>один|два...)\s/, ' 2(группа name) ') и чтобы это число в скобках магическим образом прибавилось к 2 и ещё хотелось чтобы число выбиралось только с пробелами вокруг, а земеняло, то что внутри пробелов. Буду вам признателен если поможете разобраться!


Ответы (1 шт):

Автор решения: Wiktor Stribiżew

Если все необходимые числа добавить в объект с ключами-значениями, можно использовать простой подход с помощью .replace и регулярным выражением типа (?<!\S)(пятьдесят девять|...)(?!\S), где самые длинные альтернативы перечисляются в начале, в самые короткие - в конце:

const dictionary = {
    "ноль": "0", "нуль": "0", "один": "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"};

const keys = Object.keys(dictionary);
keys.sort((a, b) => b.length - a.length);
const regex = new RegExp(String.raw`(?<!\S)(${keys.join('|')})(?!\S)`, 'gi');
// или с границей слова:
// const regex = new RegExp(String.raw`\b(${keys.join('|')})\b`, 'gi');
const w2d = (str) => {
  return str.replace(regex, (x) => dictionary[x.toLowerCase()]);
}

console.log(w2d('Пятьдесят пять секунд'));

С помощью флага i поиск становится регистронезависимым. Если число не всегда находится между пробелов, замените (?<!\S) и (?!\S) на (?<!\p{L}\p{M}*) и (?!\p{L}) (или (?<![\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]) и (?![\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}])) соответственно (Юникод-границы слова).

→ Ссылка