【问题标题】:How to parse out integers from a line with characters and integers如何从包含字符和整数的行中解析出整数
【发布时间】:2016-04-20 03:02:22
【问题描述】:

对于 C/C++ 赋值,我需要输入一行,以字符 's' 开头,后跟最多 3 个单独的整数。我的问题是,没有向量,我不知道如何解释未知数量的整数 (1-20)。

例如,测试输入如下所示:

s 1 12 20

有人建议我使用 cin.getline 并将整行作为一个字符串,但我怎么知道每个整数在字符数组中的位置,因为可能是个位数或两位数,更不用说数字了所述字符串中的整数个数?

【问题讨论】:

  • 迈克尔,我已经编辑了我的答案,所以现在应该有更多帮助了。
  • 是 C 还是 C++ 赋值?它们是两种语言。
  • 通过选择 2 种语言,解决方案集过于广泛。
  • 你想对字符串做什么?你需要取一个输入行,然后呢?

标签: c++ c


【解决方案1】:

从该行的内容构造一个std::istringstream,然后继续使用operator>>int,直到它fail()s,将每个整数填充到std::vector中(在最初使用operator>>之后,一次,照顾主角)。

【讨论】:

  • 很遗憾,分配中不允许使用向量
  • @MichaelLederer: 所以使用一个数组——std::array 如果不是禁止的话,或者int a[20]; 如果必须的话(但请注意,向量会更惯用)——然后读入一个整数,然后成功后,分配给数组的下一个可用元素,确保您不会过度运行不可扩展数组。使用getline 和字符串流对我来说似乎是一个很好的解决方案。
  • 当您需要向量替换时,我建议使用 std::deque 而不是 std::array,但主要问题当然是脑死亡限制。
  • 那么“向量是不允许的”是什么?这是一个小问题。大不了。重点是如何解析字符串。解析结果如何存储,这不是重点。
【解决方案2】:

您可以使用动态内存分配来模拟向量。最初创建一个大小为 2 的数组,使用 int *a = new int[2];

当这个数组填满时,创建一个双倍大小的新数组,将旧数组复制到新数组中,并将 a 重新分配给新数组。继续这样做,直到满足要求为止。

编辑 所以通过字符串流获取数字,如果数组填满,你可以这样做:

int changeArr(int *a, int size){
    int *b = new int[size*2];
    for(int i=0;i<size;i++){
        b[i] = a[i];
    }
    a = b;
    return size*2;
}

int getNos(istringstream ss){
    int *a = new int[2];
    int cap = 2, i=0, number;
    while(ss){
        if(i>=cap){
            cap = changeArr(a, cap);
        }
        ss >> a[i];
        i++;
    }
}

我跳过了关于第一个字符的部分,但我想你可以处理。

【讨论】:

  • 您也可以使用 Sam 在他的回答中建议的方法来获取输入。
  • 有趣。检查数组是否已满的代码是什么样的?
  • 对于这么简单的问题,我觉得这有点过分了。
【解决方案3】:

没有向量,您有几种方法。 (1) 一次读取整行并标记 使用 strtokstrsep 的行,或 (2) 使用内置于 strtol 中的标准功能来遍历字符串分隔值带有函数的指针和结束指针参数。

由于您知道格式,因此您可以轻松使用其中任何一种。上面的 1 和 2 都做同样的事情,您只需使用 strtol 中的工具在一个步骤中将 tokenizeconvert 都转换为数字。下面是一个处理字符串的简短示例,该字符串后跟每行的未知位数:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>

enum { BASE = 10, MAXC = 512 };

long xstrtol (char *p, char **ep, int base);

int main (void) {

    char buf[MAXC] = "";

    while (fgets (buf, MAXC, stdin)) {   /* for each line of input */
        char *p, *ep;   /* declare pointers */
        p = buf;        /* reset values */
        errno = 0;

        printf ("\n%s\n", p); /* print the original full buffer */

        /* locate 1st digit in string */
        for (; *p && (*p < '0' || '9' < *p); p++) {}
        if (!*p) {  /* validate digit found */
            fprintf (stderr, "warning: no digits in '%s'\n", buf);
            continue;
        }

        /* separate integer values */
        while (errno == 0)
        {   int idx = 0;
            long val;
            /* parse/convert each number in line into long value */
            val = xstrtol (p, &ep, BASE);
            if (val < INT_MIN || INT_MAX < val) {   /* validate int value */
                fprintf (stderr, "warning: value exceeds range of integer.\n");
                continue;
            }
            printf ("  int[%2d]: %d\n", idx++, (int) val);  /* output int */

            /* skip delimiters/move pointer to next digit   */
            while (*ep && *ep != '-' && (*ep < '0' || *ep > '9')) ep++;
            if (*ep)
                p = ep;
            else
                break;
        }
    }

    return 0;
}

/** a simple strtol implementation with error checking.
 *  any failed conversion will cause program exit. Adjust
 *  response to failed conversion as required.
 */
long xstrtol (char *p, char **ep, int base)
{
    errno = 0;

    long val = strtol (p, ep, base);

    /* Check for various possible errors */
    if ((errno == ERANGE && (val == LONG_MIN || val == LONG_MAX)) ||
        (errno != 0 && val == 0)) {
        perror ("strtol");
        exit (EXIT_FAILURE);
    }

    if (*ep == p) {
        fprintf (stderr, "No digits were found\n");
        exit (EXIT_FAILURE);
    }

    return val;
}

xstrtol 函数只是将正常的错误检查转移到一个函数中以整理代码主体)

示例输入

$ cat dat/varyint.txt
some string 1, 2, 3
another 4 5
one more string 6 7 8 9
finally 10

使用/输出示例

$ ./bin/strtolex <dat/varyint.txt

some string 1, 2, 3

  int[ 0]: 1
  int[ 1]: 2
  int[ 2]: 3

another 4 5

  int[ 0]: 4
  int[ 1]: 5

one more string 6 7 8 9

  int[ 0]: 6
  int[ 1]: 7
  int[ 2]: 8
  int[ 3]: 9

finally 10

  int[ 0]: 10

您可以进行一些整理,但此方法可用于可靠地解析未知数量的值。如果您有任何问题,请查看并告诉我。

【讨论】:

    【解决方案4】:

    由于不允许使用向量,因此您需要先找出一行中有多少个数字,然后才能创建一个数组来保存它们。

    我不会只给你完整的代码,因为这是家庭作业,但我会告诉你我会做些什么来解决你的问题。

    如果您的行总是如下所示:“s number”或“s number number”或“s number number number”,那么您可以通过计算空格轻松找到行中数字的数量!

    任何带有一个数字的字符串中都会有一个空格(在 s 和那个数字之间),第一个数字后面的每个数字还有一个空格。

    那么让我们数一下空格吧!

    int countSpaces(string s) {
        int count = 0;
    
        for (int i = 0; i < s.size(); i++) {
            if (s[i] == ' ') {
                count++;
            }
        }
    
        return count;
    }
    

    传递这些字符串:

    string test1 = "s 123 4 99999";
    string test2 = "s 1";
    string test3 = "s 555 1337";
    

    countSpaces函数会给我们:

    3
    1
    2
    

    有了这些信息,我们可以创建一个大小正确的数组来保存每个值!


    编辑

    现在我意识到您无法从字符串中获取数字。

    我会做的是使用上述方法查找行中的数字数量。然后,我将使用std::string.find() 函数来确定字符串中的位置以及是否有空格。

    假设我们有这条线:s 123 45 678

    countSpaces 会告诉我们我们有 3 个数字。

    然后我们创建一个数组来保存我们的三个数字。我还会切断s 部分,这样您就不必再担心了。请注意,您可以使用std::stoi 将字符串转为数字!

    现在我们可以在 find(' ') 不返回 -1 时循环。

    在我们的循环中,我会将子字符串从 0 带到第一个空格,如下所示:

    num = std::stoi( myLine.substr(0, myLine.find(' ') )
    

    然后你就可以剪掉刚刚使用的部分了:

    myLine = myLine.substr( myLine.find(' ') );
    

    这会从你的字符串前面抓取一个数字,然后从字符串中剪掉那个数字,然后在字符串中还有空格的时候重复这个过程。

    编辑:

    如果您不能保证每个数字之间有一个空格,那么您可以在执行此方法之前删除多余的空格,或者您可以在 countSpaces 循环期间执行此操作。此时,调用countNums 之类的函数会更有意义。

    删除空格并用一个空格替换它们的示例函数:

    void removeExtraSpaces(string s) {
        bool inSpaces = (s[0] == ' ');
    
        for (int i = 1; i < s.size(); i++) {
    
            if (s[i] == ' ') {
    
                if(inSpaces) {
                    s.erase(i); 
                } else { 
                    inSpaces = true;
                }
    
            } else if(inSpaces) {
                inSpaces = false;
            }
    
        }
    }
    

    【讨论】:

    • 这很有意义!谢谢!
    • @MichaelLederer 不客气!记得为您认为有帮助的答案(不仅仅是您选择的答案)点赞,并记得将答案标记为“答案”,因为人们会花费大量时间来提供帮助!
    • 请注意,该问题并不能保证每个数字前都有 一个 空格,因此您应该将获得的空格数视为 最大 预期数字输入数字的数量,而不是精确的实际数字数量。
    • @CiaPan 我添加了一些代码,可以删除多余的空格。
    猜你喜欢
    • 2013-12-08
    • 1970-01-01
    • 1970-01-01
    • 2015-12-30
    • 1970-01-01
    • 1970-01-01
    • 2012-08-11
    • 1970-01-01
    相关资源
    最近更新 更多