【问题标题】:How to avoid Switch Case & sscanf Function如何避免 Switch Case 和 sscanf 功能
【发布时间】:2014-03-15 05:13:33
【问题描述】:

我正在研究 C++。我正在编写日期格式的代码。使用 with,我们可以从任何其他日期格式中获取默认日期格式。所以我为这个任务找到了 240 种日期格式。所以 M 想使用 switch case 和 sscanf 函数。每个案例都有 sscanf 函数来分隔日、月、年。所以我需要 240 个案例和 240 个 sscanf 函数。有什么方法可以避免大量的 swtich 和 sscanf?如果大家有什么想法,请告诉我。

case 0:
    sscanf(tsdate.c_str(),"%2d/%2d/%4d",&day,&month,&year);
    break;
case 1:
    sscanf(tsdate.c_str(),"%2d-%2d-%4d",&month,&day,&year);
    break;
case 2:
    sscanf(tsdate.c_str(),"%2d %2d %4d",&day,&month,&year);
    break;
case 3:
    sscanf(tsdate.c_str(),"%2d/%2d/%2d",&day,&month,&year);
    coryear(year);
    break;
case 4:
    sscanf(tsdate.c_str(),"%2d/%2d/%2d",&year,&month,&day); 
    coryear(year);
    break;

像上面一样,我想放 240 个 case 和 240 个 sscanf。请告诉我如何避免很多情况。

【问题讨论】:

  • 为什么有240个案例是个问题?创建起来很乏味,但一旦创建,它应该需要很少的维护,并且总是非常快。
  • y-m、m-d之间的分隔符是否相同?
  • 你不能用正则表达式吗?如果您使用它们,您可以专注于数字的顺序,而不必处理分隔符。
  • 你能不能也不要扫描分隔符(使用扫描集,如%[- /]),这样你就可以减少案例的数量。如果做不到这一点,您应该使用结构类型的数组来描述如何处理 240 个案例中的每一个(尽管我承认我不确定您如何获得 240 个选项)。写出 240 个sscanf() 语句是……我们应该说“次优”吗?另外,您是否意识到%2d 转换规范将允许空格和前导零;它仅表示如果字符串以"123…" 开头,则转换后的值将是12,而不是123。您的案例 0 将匹配 " 26/ 12/ 23456"
  • 另外,如果您正在使用 POSIX 系统,您应该查看 sscanf() 规范中的 n$ 部分。

标签: c++


【解决方案1】:

你无法避免 switch case,但你可以创建多个函数来避免 sscanf:

void scanDayFirst(string format)
{
        sscanf(tsdate.c_str(),format,&day,&month,&year);
        break;
}
void scanMonthFirst(string format)
{
        sscanf(tsdate.c_str(),format,&month,&day,&year);
        break;
}

等等……

结果会是这样的:

    case 0:
        scanDayFirst("%2d/%2d/%4d");
    case 1:
       scanDayFirst("%2d-%2d-%4d");
    case 2:
        scanDayFirst("%2d %2d %4d");
    case 3:
        scanDayFirst("%2d.%2d.%4d");

【讨论】:

    【解决方案2】:
    enum { ITEM_YEAR, ITEM_MONTH, ITEM_DAY, NUM_ITEMS };
    struct date_format { char const *fmt; int items[NUM_ITEMS]; };
    
    struct date_format const formats[] = 
        { { "%2d/%2d/%4d", { ITEM_DAY, ITEM_MONTH, ITEM_YEAR } }
        , { "%2d-%2d-%4d", { ITEM_MONTH, ITEM_DAY, ITEM_YEAR } }
        /* etc. */
        };
    
    int parts[NUM_ITEMS];   /* Instead of year,month,day */
    sscanf(tsdate.c_str(), formats[x].fmt, 
        &parts[formats[x].items[0]],
        &parts[formats[x].items[1]],
        &parts[formats[x].items[2]]);
    

    如果你想跳过一个项目,或者添加额外的项目等等,你可以扩展它来拥有 ITEM_NONE。

    注意。如果这是 C++,那么考虑使用流输入而不是 sscanf。

    【讨论】:

    • 在年份被编码为 2 位数字的情况下,OP 称为 coryear(year)...这可以很容易地添加到我喜欢的表驱动解决方案中。
    【解决方案3】:

    与其枚举所有情况,不如考虑使用自定义语言作为格式规范:

    Date x = parseDate(user_input, "dd-mm-yyyy");
    

    它将使函数更短、更易于记录和更易于使用,同时提高使用它的代码的可读性。这个想法是使用类似的代码

    yyyy ............. 4-digits year
    yy ............... 2-digits year with automatic century computation
    mm ............... 2-digits month
    m ................ 1 or 2 digits month
    dd ............... 2-digits day
    d ................ 1 or 2 digits day
    anything else .... mandatory character
    

    一个简单的实现可以是

    Date parseDate(const std::string& input, const std::string& format) {
        const char *src = input.c_str();
        const char *fmt = format.c_str();
        int year=-1, month=-1, day=-1;
        while (*fmt) {
            if (!*src) throw invalid_date(input, format);
            if (strncmp(fmt, "yyyy", 4) == 0) {
                fmt += 4;
                year = getInt(src, 4);
            } else if (strncmp(fmt, "yy", 2) == 0) {
                fmt += 2;
                year = guess_century(getInt(src, 2));
            } else if (strncmp(fmt, "mm", 2) == 0) {
                fmt += 2;
                month = getInt(src, 2);
            } else if (fmt[0] == 'm') {
                fmt += 1;
                month = getInt(src, -1);
            } else if (strncmp(fmt, "dd", 2) == 0) {
                fmt += 2;
                day = getInt(src, 2);
            } else if (fmt[0] == 'd') {
                fmt += 1;
                day = getInt(src, -1);
            } else {
                if (src[0] != fmt[0]) throw invalid_date(input, format);
                src++; fmt++;
            }
       }
       if (*src || year == -1 || month == -1 || day == -1)
         throw invalid_date(input, format);
       return Date(year, month, day);
    }
    

    注意:未经测试

    【讨论】:

    • 非常感谢。你的代码对我很有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-12
    相关资源
    最近更新 更多