简体   繁体   中英

Increment numbers in char array separated by different delimiters

I have string like this 1-2,4^,14-56
I am expecting output 2-3,5^,15-57

char input[48];
int temp;
char *pch;

pch = strtok(input, "-,^");

while(pch != NULL)
{
    char tempch[10];
    temp = atoi(pch);
    temp++;
    itoa(temp, tempch, 10);
    memcpy(pch, tempch, strlen(tempch));
    pch = strtok(NULL, "-,^");
}

After running through this if I print input it prints only 2 which is first character of the updated string. It does not print all characters in the string. What is the problem with my code?

There are two major problems with this code: First of all,

pch = strtok(input, ",");

When applied to the string 1-2,4^,14-56 will return the token 1-2 .

When you call atoi("1-2") you'll get 1 , which gets converted to 2 .

You can fix this by changing the first strtok to pch = strtok(NULL, "-,^");

Second of all, strtok modifies the string, which means that you lose the original delimiter found. As this looks like a homework exercise, I'll leave you to figure out how to get around this.

For plain C, use the library function strtod . Other than atoi , this can update a pointer to the next unparsed character:

long strtol (const char *restrict str , char **restrict endptr , int base );
...
The strtol() function converts the string in str to a long value. [...] If endptr is not NULL, strtol() stores the address of the first invalid character in *endptr .

Since there may be more than one 'not-a-digit' character between the numbers, skip them with the library function isdigit . I placed this at the start of the loop so it would not accidentally convert a string such as -2,3 to -1,4 -- the initial -2 would be picked up first! (And if that is a problem elsewhere, there is also a strtoul .)

Since it appears you want the result in a char string, I use sprintf to copy the output into a buffer, which must be large enough for your possible input plus extra characters caused by a decimal overflow.

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

int main (void)
{
    char *inputString = "1-2,4^,14-56";
    char *next_code_at = inputString;
    long result;
    char dest[100], *dest_ptr;

    printf ("%s\n", inputString);

    dest[0] = 0;
    dest_ptr = dest;
    while (next_code_at && *next_code_at)
    {
        while (*next_code_at && !(isdigit(*next_code_at)))
        {
            dest_ptr += sprintf (dest_ptr, "%c", *next_code_at);
            next_code_at++;
        }
        if (*next_code_at)
        {
            result = strtol (next_code_at, &next_code_at, 10);
            if (errno)
            {
                perror ("strtol failed");
                return EXIT_FAILURE;
            } else
            {
                if (result < LONG_MAX)
                    dest_ptr += sprintf (dest_ptr, "%ld", result+1);
                else
                {
                    fprintf (stderr, "number too large!\n");
                    return EXIT_FAILURE;
                }
            }
        }
    }
    printf ("%s\n", dest);

    return EXIT_SUCCESS;
}

Sample run:

Input:  1-2,4^,14-56
Output: 2-3,5^,15-57

strtok modifies the string you pass to it. Either use strchr or something like that to find the delimiters or make a copy of the string to work on.

I think this could by easier using regular expressions(and C++ instead of C of course):

Complete exmaple:

#include <iostream>
#include <iterator>
#include <regex>
#include <string>

int main()
{

    // Your test string.
    std::string input("1-2,4^,14-56");
    // Regex representing a number.
    std::regex number("\\d+");

    // Iterators for traversing the test string using the number regex.
    auto ri_begin = std::sregex_iterator(input.begin(), input.end(), number);
    auto ri_end = std::sregex_iterator();


    for (auto i = ri_begin; i != ri_end; ++i)
    {
        std::smatch match = *i;                             // Match a number.
        int value = std::stoi(match.str());                 // Convert that number to integer.
        std::string replacement = std::to_string(++value);  // Increment 1 and convert to string again.

        input.replace(match.position(), match.length(), replacement); // Finally replace.
    }

    std::cout << input << std::endl;

    return 0;
}

Output:

2-3,5^,15-57

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM