如何在使用标准C拒绝无效数字的同时将罗马数字转换为int? [英] How to convert Roman numerals to int while rejecting invalid numbers using standard C?

查看:94
本文介绍了如何在使用标准C拒绝无效数字的同时将罗马数字转换为int?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

适当的含义罗马数字 变化.为了简单起见(没有Unicode,没有乘法原理,没有双减法,没有横线,没有大数等),有效的罗马数字由

What it means to be proper Roman numerals may vary. For simplicity (no Unicode, no multiplicative principle, no double subtractives, no overbars, no large numbers, etc) for the sake of this question, valid Roman numerals are defined by the regex:

^(M{0,3})(D?C{0,3}|CM|CD)(L?X{0,3}|XC|XL)(V?I{0,3}|IX|IV)$

带有POSIX regexec() 的代码示例. regex匹配使用严格"规则表示的1..3999范围内的罗马数字.

Code example with POSIX regexec(). The regex matches Roman numerals in 1..3999 range represented using "strict" rules.

如果我们不需要拒绝无效数字,有许多解决方案可以转换罗马数字,例如:

There are many solutions that can convert Roman numerals if we don't need to reject invalid numerals, for example:

int roman_numeral_value(unsigned char c)
{
  switch(toupper(c)) {
  case 'I': return 1;
  case 'V': return 5;
  case 'X': return 10;
  case 'L': return 50;
  case 'C': return 100;
  case 'D': return 500;
  case 'M': return 1000;
  default: return 0; // error
  }
}

int roman_numeral_to_int(const char *s, int size)
{
  int total = 0, prev = 0;
  for (int i = size-1; i >= 0; --i) { // in reverse order
    int value = roman_numeral_value(s[i]);
    total += value < prev ? -value : value; // subtract if necessary
    prev = value;
  }
  return total;
}

它适用于有效的罗马数字.但是roman_numeral_to_int()接受正则表达式拒绝的数字,例如IIIII.是否有类似的简单跨平台解决方案,不需要 pcre_exec() 或其他有效的外部依赖项有效的罗马数字,而用于它们?

It works for valid Roman numerals. But roman_numeral_to_int() accepts numerals such as IIIII that are rejected by the regex. Is there a similarly simple cross-platform solution that doesn't require pcre_exec() or other external dependencies that works for valid Roman numerals and only for them?

推荐答案

使用strcmp()或换句话说,将字符串往返.

Use strcmp() or in other words, round-trip the string.

首先考虑相反的问题,数字->字符串.

First consider the reverse problem, number --> string.

有很多方法可以有效地将整数转换为罗马数字字符串.让我们称之为:

There are many ways to efficiently convert an integer to a string of Roman numerals. Let us call it:

// return false on error due to `value` range error or scant `size`
bool roman_int_to_string(char *dest, size_t size, int value);

除了字母 case 外,规范的罗马数字字符串与int之间还存在一对一的关系.只需将源字符串转换为int,然后将int转换为另一个测试字符串.如果这些字符串匹配,那么我们就有赢家.

Aside from letter case concerns, there is a one-to-one relationship between a canonical Roman number string and an int. Simply convert the source string to an int and then the int into another test string. If these strings match, we have a winner.

#define ROMAN_STRING_N 20
int roman_numeral_to_int_with_validate(const char *s, int size, bool *is_canonical) {
  int value = roman_numeral_to_int(s, size);

  char test[ROMAN_STRING_N];
  *is_canonical = roman_int_to_string(test, sizeof test, value);
  if (*is_canonical) {
    if (strcmp(s, test)) {  // Or use a case insensitive compare as desired
      *is_canonical = false;
    }
  }

  return value;
}


课程:我确实编写了直接验证功能.要测试它,我需要反数roman_int_to_string().随机字符串生成器迅速显示出许多令人惊讶的错误,例如"CMC""CMCD"以及OP的"IIII".最后,使用简单的string-to-int和int-to-string函数对然后进行字符串比较是最灵活的.


Lesson: I did code up a direct validation function. To test it I needed the inverse roman_int_to_string(). A random string generator rapidly showed many surprising errors like "CMC" and "CMCD" as well as OP's "IIII". In the end, using a simplistic string-to-int and int-to-string function pair and then doing a string compare was the most resilient.

这篇关于如何在使用标准C拒绝无效数字的同时将罗马数字转换为int?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆