Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.62/47: Рейтинг темы: голосов - 47, средняя оценка - 4.62
0 / 0 / 0
Регистрация: 27.01.2020
Сообщений: 1

Замена римских букв на арабские цифры в строке

27.01.2020, 21:56. Показов 10652. Ответов 5

Студворк — интернет-сервис помощи студентам
Напишите программу, которая заменяет в переданной её символьной строке все записанные в римской системе счисления, на те же числа, записанные арабскими цифрами.

Входные данные
Входная строка содержит текст, содержащий (возможно) запись чисел в римской системе счисления.

Выходные данные
Нужно заменить во всей строке числа, записанные в римской системе счисления, на те же числа, записанные арабскими цифрами.

Примеры

входные данные:
In MMXIV Vasya graduated from school.


выходные данные:
In 2014 Vasya graduated from school.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
27.01.2020, 21:56
Ответы с готовыми решениями:

Перевод римских чисел в арабские
Доброй ночи всем. Нужны наиболее рациональные и простые в реализации идеи для решения задачи. Дан текст из заглавных латинских букв за...

Из римских чисел в арабские в файле
Здравствуйте. Дана задача - в данном тексте заменить все римские числа на арабские. Вот я и не могу понять, каким образом в файловом потоке...

Перевод римских цифр в арабские
Нужно написать программу перевода римских чисел в арабские. Есть эта программа на c#, но нужна на c++. Помогите пожалуйста, горю! Вот эта...

5
Злостный нарушитель
 Аватар для Verevkin
10355 / 5770 / 1274
Регистрация: 12.03.2015
Сообщений: 26,667
27.01.2020, 22:59
Сюда читай.
0
Мозгоправ
 Аватар для L0M
1745 / 1039 / 468
Регистрация: 01.10.2018
Сообщений: 2,138
Записей в блоге: 2
31.01.2020, 00:53
Verevkin, там, куда вы послали ТС читать, решение сильно с гнильцой. Что бы далеко не ходить, делаю копипасту сюда обоих вариантов:

Вариант 1
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int romanToInt(string s) {
 
    int total = 0;
    for (int i = 0; i < s.length(); i++) {
 
        //1.The letters are arranged from left to right in descending order of value to form a number
        if (integer_of(s[i]) <= interger_of[s[i]]) {
            total += integer_of(s[i]);
        }
        //2.when you see a lower value in front of a higher value(subtract)
        else {
            total += integer_of(s[i]);
        }
    }
    return total;
}
Вариант 2
C++
1
2
3
4
5
6
7
8
9
10
11
int romanToInt(string s) {
 
    map<char, int> m = { {'I', 1}, {'V', 5}, {'X', 10}, {'L', 50}, {'C', 100}, {'D', 500}, {'M', 1000} };
 
    int total = 0;
    for (int i = 0; i < s.length(); i++) {
        if (m[s[i + 1]] <= m[s[i]])  total += m[s[i]];
        else  total -= m[s[i]];
    }
    return total;
}
Вариант 1 содержит банальные синтаксические ошибки (подразумевая, что функция integer_of() где-то таки определена). Если в строке 7 поправить скобки: if (integer_of(s[i]) <= integer_of(s[i])), условие будет всегда истинным. Если же, подглядывая в вариант 2, докорректировать до if (integer_of(s[i + 1]) <= integer_of(s[i])), то UB - см. ниже вариант 2.

В варианте 2 выход за границу строки (UB) при анализе последнего символа: s[i + 1]. Код работает только потому, что в конкретной реализации std::string обращение элементу строки s[s.length()] возвращает концевой '\0', а не, допустим, вызывает исключение std::out_of_range.

Далее, цитирую: best way to store the table to convert roman numerals to their corresponding integer values is by using a hash map. Ок, не вопрос. Но если этот map - просто справочная таблица, то надо добавить квалификаторы static const. Но, как говорится, фигвам - это жилище такое у индейцев. Сия таблица активно изменяется при вызовах std::map::operator[](). В мапу в качестве ключей добавляются все буквы (без дублирования), имеющиеся в строке (кроме тех, которые указаны при инициализации), включая символ '\0', со значением значения 0. Опять-таки спасает ситуацию то, что std::map добавляет ключ со значением по умолчанию 0.

Другими нежелательными эффектами является выделение памяти для хранения совершенно ненужных пар ключ-значение и некоторое увеличение времени поиска ключей.

Т.е. надо было использовать метод std::map::find().

Наконец, hash map, см. цитату выше, это std::unordered_map, а std::map - это бинарное дерево.

Ну и уж совсем напоследок, параметр в romanToInt() лучше передавать как константную ссылку. Это, извините, сейчас знают дети в старшей группе детсада.

Добавлено через 18 минут
SSDsssdd, кроме того, эти "решения" работают со всей строкой. Т.е. если функции romanToInt() напрямую скормить строку "In MMXIV Vasya graduated from school.", то функция вернёт число 2020.

Следовательно, для решения вашей задачи необходимо входную строку разбивать на части, каждую часть проверять, что она является числом, записанным римскими цифрами, а потом уже скармливать функции.

Кстати, алгоритм, реализованный в romanToInt(), трактует римскую запись числа несколько шире, чем это принято. Например, IIIIIIII это 8, и IIIIIV тоже 8.
0
Злостный нарушитель
 Аватар для Verevkin
10355 / 5770 / 1274
Регистрация: 12.03.2015
Сообщений: 26,667
31.01.2020, 08:30
Цитата Сообщение от L0M Посмотреть сообщение
там, куда вы послали ТС читать, решение сильно с гнильцой.
Критикуешь - предлагай свой вариант.
Вот функция на pascal. Можно и по ней запилить:
Delphi
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
function RomanToInt(const S: string): Longint;
const
  RomanChars = ['C', 'D', 'I', 'L', 'M', 'V', 'X'];
  RomanValues: array['C'..'X'] of Word =
  (100, 500, 0, 0, 0, 0, 1, 0, 0, 50, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 10);
var
  Index, Next: Char;
  I: Integer;
  Negative: Boolean;
begin
  Result := 0;
  I := 0;
  Negative := (Length(S) > 0) and (S[1] = '-');
  if Negative then
    Inc(I);
  while (I < Length(S)) do
  begin
    Inc(I);
    Index := UpCase(S[I]);
    if Index in RomanChars then
    begin
      if Succ(I) <= Length(S) then
        Next := UpCase(S[I + 1])
      else
        Next := #0;
      if (Next in RomanChars) and (RomanValues[Index] < RomanValues[Next]) then
      begin
        Inc(Result, RomanValues[Next]);
        Dec(Result, RomanValues[Index]);
        Inc(I);
      end
      else
        Inc(Result, RomanValues[Index]);
    end
    else
    begin
      Result := 0;
      Exit;
    end;
  end;
  if Negative then
    Result := -Result;
end;
0
place status here
 Аватар для gunslinger
3190 / 2227 / 640
Регистрация: 20.07.2013
Сообщений: 6,022
31.01.2020, 10:04
Перевести римские числа в арабские, и наоборот
C++
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
UINT RomanToArabic(String roman_number)
{
  const count = 7, rn = 18;
  String roman = "IVXLCDM", cond = "";
  UINT arabic[count] = {1, 5, 10, 50, 100, 500, 1000}, result = 0, test = 0;
  int i, j, length = roman_number.Length();
  UINT trans_table[rn+1][count] = {
                                   6,  5,  4,  3,  2,  1,  1,
                                  rn, rn, rn, rn,  7, rn,  7,
                                  rn, rn,  9, rn,  8,  7,  7,
                                  rn, rn,  9, rn, 10,  1,  1,
                                  12, rn, 11,  9, 10,  1,  1,
                                  12, rn, 13,  3,  2,  1,  1,
                                  14, 12,  4,  3,  2,  1,  1,
                                  rn, rn, rn, rn, rn, rn,  7,
                                  rn, rn, rn, rn, 15,  7,  7,
                                  rn, rn, rn, rn, 10,  1,  1,
                                  rn, rn, rn, rn,  8,  7,  7,
                                  rn, rn, 16,  9, 10,  1,  1,
                                  rn, rn, 13,  3,  2,  1,  1,
                                  rn, rn, 11,  9, 10,  1,  1,
                                  17, 12, 13,  3,  2,  1,  1,
                                  rn, rn, rn, rn, rn,  7,  7,
                                  rn, rn, rn,  9, 10,  1,  1,
                                  rn, 12, 13,  3,  2,  1,  1,
                                  rn, rn, rn, rn, rn, rn, rn
                                };
  for (i = length; i > 0; i--)
    for (j = 0; j < count; j++)
      if (roman_number[i] == roman[j+1])
        test = trans_table[test][j];
 
  if (test > 0 && test < rn)
  {
    for (i = 1; i <= length; i++)
      cond += "0";
 
    for (i = length; i > 0; i--)
      for (j = 0; j < count; j++)
        if (roman_number[i] == roman[j+1])
          cond[i] = j;
 
    result += arabic[ cond[length] ];
 
    for (i = length; i > 1; i--)
    {
      if (cond[i-1] >= cond[i])
        result += arabic[ cond[i-1] ];
      else
        result -= arabic[ cond[i-1] ];
    }
  }
 
  return result;
}
0
Мозгоправ
 Аватар для L0M
1745 / 1039 / 468
Регистрация: 01.10.2018
Сообщений: 2,138
Записей в блоге: 2
01.02.2020, 01:27
Цитата Сообщение от Verevkin Посмотреть сообщение
Критикуешь - предлагай свой вариант.
Свой вариант потребовал некоторых изысканий. Поскольку те решения, которые выдаёт Гугл на первой странице, либо гнилые, либо работают некорректно. Даже статья в Википедии неточна: в соответствии с ней корректными числами будут IVI или XLXIVI, что очевидно неправильно. Кстати онлайн-конверторы тоже грешат некорректной работой.

В итоге родился следующий код:
C++
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <iostream> 
#include <string> 
#include <map>
#include <regex>
 
using namespace std;
 
/*
Перевод из римской нотации
 
Обратное преобразование будет осуществляться в обратном порядке. Строку,
представляющую собой римскую запись числа, прежде всего нужно разделить по
десятичным разрядам, а затем найдём десятичные цифры, соответствующие этим
разрядам.
 
Задача разделения по разрядам теперь будет сложнее. Дело в том, что не каждая
строка, составленная из римских цифр, будет правильной римской записью
некоторого числа (в отличие от десятичной записи, в которой правильной будет
любая последовательность десятичных цифр).
 
В соответствии с правилами формирования римской записи чисел правильная запись
представляет собой четыре группы римских цифр, составленных вместе. Первая
(расположенная слева) — группа, обозначающая тысячи, затем идёт группа сотен,
затем десятков, и, наконец, единиц.
 
Удачным решением было бы использовать регулярные выражения для разделения
римской записи на группы цифр по разрядам. Для каждой группы нужно составить
шаблон и заключить его в захватывающие скобки. Шаблоны для тысяч, сотен,
десятков и единиц, составленные вместе, дадут регулярное выражение, которому
должна соответствовать римская запись целиком. Поэтому в регулярное выражение
следует добавить привязки к началу и концу строки.
 
Приступим к созданию шаблона для разряда единиц. Решение, которое первым
приходит в голову — перечислить все альтернативы:
(|I|II|III|IV|V|VI|VII|VIII|IX). Обратите внимание на пустую альтернативу, с
которой начинается перечисление: группа единиц в римской записи может быть и
пустой. Это решение можно немного упростить, если использовать квантификаторы.
Для цифр от 0 до 3 можно написать I{0,3} вместо |I|II|III, для цифр от 5 до 8
годится VI{0,3} вместо V|VI|VII|VIII. Таким образом, для разряда единиц получаем
шаблон (I{0,3}|IV|VI{0,3}|IX). Его можно дополнительно упростить, объединив
первую альтернативу с третьей, а вторую с четвёртой: (V?I{0,3}|I[VX]).
 
Для десятков и сотен получаются точно такие же шаблоны, только составленные из
других римских цифр: (L?X{0,3}|X[LC]) (десятки) и (D?C{0,3}|C[DM]) (сотни). Для
разряда тысяч шаблон совсем простой: (M{0,3}).
 
Итак, для целой римской записи получаем такое регулярное выражение:
^(M{0,3})(D?C{0,3}|C[DM])(L?X{0,3}|X[LC])(V?I{0,3}|I[VX])$.
 
Источник: http://mech.math.msu.su/~shvetz/54/inf/perl-problems/chRomanNumerals_sIdeas.xhtml
 
*/
 
 
bool roman2uint(const char *str, unsigned int &result, bool ignore_case = true) {
    typedef map<char, int> Mapper;
 
    static const Mapper m = { {'I', 1}, {'V', 5}, {'X', 10}, {'L', 50}, {'C', 100}, {'D', 500}, {'M', 1000} };
    static const char *pattern = R"(^(M{0,3})(D?C{0,3}|C[DM])(L?X{0,3}|X[LC])(V?I{0,3}|I[VX])$)";
 
    result = 0;
    if (str == nullptr || *str == '\0')
        return false;
 
    regex::flag_type flag = regex_constants::ECMAScript;
    if (ignore_case)
        flag |= regex_constants::icase;
    regex re(pattern, flag);
    cmatch mres;
 
    if (regex_match(str, mres, re)) {
        for (size_t i = 1; i < mres.size(); ++i) {
            if (mres.length(i) == 0)
                continue;
            const char *pch = mres[i].first;
            Mapper::const_iterator it, it_prev = m.end();
            while (pch != mres[i].second) {
                it = m.find(toupper(*pch));
                if (it_prev == m.end() || it_prev->second >= it->second)
                    result += it->second;
                else
                    result += it->second - it_prev->second * 2;
 
                it_prev = it;
                ++pch;
            }
 
        }
        return true;
    }
    return false;
}
 
 
int main()
{
    string str;
    const char *tail = nullptr;
    unsigned int result;
    do {
        cout << "> ";
        getline(cin, str);
        if (roman2uint(str.c_str(), result))
            cout << result << endl;
        else
            cout << "error" << endl;
    } while (str.size() > 0);
 
}
Энтузиасты могут потестировать с пристрастием. Критика и баг-репорты принимаются
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
01.02.2020, 01:27
Помогаю со студенческими работами здесь

Перевод римских чисел в арабские и наоборот
Я в Си программирую недавно, помогите пожалуйста решить.... Разработать программу для перевода чисел, записанных римскими цифрами в...

Проверить, встречаются ли в строке хотя бы по одному разу все арабские цифры
Для введенной с клавиатуры строки символов, содержащей буквы латинского алфавита, арабские цифры, знаки препинания и пробелы, проверить,...

Замена букв на цифры
Заменить буквы на цифры, начиная с числа 15. а - 15 б - 16 в - 17 и т.д Добавлено через 19 секунд Напишите, пожалуйста, код.

Замена букв на цифры!
Вот код #include &lt;iostream&gt; #include &lt;algorithm&gt; #include &lt;string&gt; int main(void){ std::string s = &quot;abcdef&quot;; ...

Замена букв в строке на сочетание букв
Здравствуйте. Дана задача: дана строка которая содержит определенный текст который вводится с клавиатуры, в этом тексте необходимо...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Новые блоги и статьи
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
Реалии
Hrethgir 01.03.2026
Нет, я не закончил до сих пор симулятор. Эта задача сложнее. Не получилось уйти в плавсостав, но оно и к лучшему, возможно. Точнее получалось - но сварщиком в палубную команду, а это значит, в моём. . .
Ритм жизни
kumehtar 27.02.2026
Иногда приходится жить в ритме, где дел становится всё больше, а вовлечения в происходящее — всё меньше. Плотный график не даёт вниманию закрепиться ни на одном событии. Утро начинается с быстрых,. . .
SDL3 для Web (WebAssembly): Сборка библиотек: SDL3, Box2D, FreeType, SDL3_ttf, SDL3_mixer и SDL3_image из исходников с помощью CMake и Emscripten
8Observer8 27.02.2026
Недавно вышла версия 3. 4. 2 библиотеки SDL3. На странице официальной релиза доступны исходники, готовые DLL (для x86, x64, arm64), а также библиотеки для разработки под Android, MinGW и Visual Studio. . . .
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru