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

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

27.01.2020, 21:56. Просмотров 2314. Ответов 5

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

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

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

Примеры

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


выходные данные:
In 2014 Vasya graduated from school.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
27.01.2020, 21:56
Ответы с готовыми решениями:

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

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

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

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

5
Продавец времени
4752 / 2581 / 585
Регистрация: 12.03.2015
Сообщений: 12,562
27.01.2020, 22:59 2
Сюда читай.
0
Мозгоправ
1589 / 928 / 423
Регистрация: 01.10.2018
Сообщений: 1,935
Записей в блоге: 2
31.01.2020, 00:53 3
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
Продавец времени
4752 / 2581 / 585
Регистрация: 12.03.2015
Сообщений: 12,562
31.01.2020, 08:30 4
Цитата Сообщение от 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
случайный прохожий
1497 / 986 / 372
Регистрация: 20.07.2013
Сообщений: 2,869
31.01.2020, 10:04 5
Перевести римские числа в арабские, и наоборот
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
Мозгоправ
1589 / 928 / 423
Регистрация: 01.10.2018
Сообщений: 1,935
Записей в блоге: 2
01.02.2020, 01:27 6
Цитата Сообщение от 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
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
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){ ...

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


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

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.