【问题标题】:Split string by one of few delimiters? [closed]通过少数分隔符之一拆分字符串? [关闭]
【发布时间】:2016-07-30 14:32:26
【问题描述】:

我有这个

A > B,或A < B,或A==B

使用strtok 我将销毁数据,我的目标是获得某种可以检查的结构:

  1. 我有什么样的分隔符
  2. 访问它的两侧(A 和 B)。

所以:

if ( > )
do something with A and B
else if (==)
do something with A and B 

我知道这听起来很简单,但它总是很麻烦。

编辑:

我所做的是这个,对于这项任务来说似乎太长了:

for (int k=1;k<strlen(p);k++)
{

    char left[4]="" ;
    char right[12]="" ;



    switch(p[k])
    {


        case '>' :
        {
            long num =strstr(p,">") - p ;
            strncpy(left,p,num);
            strncpy(right,p+num+1,strlen(p)-num-1);


            break;
        }



        case '<' :
        {
            long num =strstr(p,"<") - p ;
            strncpy(left,p,num);
            strncpy(right,p+num+1,strlen(p)-num-1);


            break;
        }


        case '=' :

        {
            long num =strstr(p,"=") - p ;
            strncpy(left,p,num);
            strncpy(right,p+num+1,strlen(p)-num-1);


            break;
        }

        case '!' :
        {
            long num =strstr(p,"!") - p ;
            strncpy(left,p,num);
            strncpy(right,p+num+1,strlen(p)-num-1);


            break;
        }

        default :
        {}
    }


}

【问题讨论】:

  • @mik1904 它不适用于“==”,它不是单个字符。
  • 由于可能有也可能没有空格分隔符(或者看起来如此),仅仅 指针 是不够的。您需要一个 result 结构,其中至少包含一个指向每个标记的开头及其长度的指针,或者,将每个标记复制到一个新字符串中。代码可以非常简单;到目前为止你有什么?
  • 这是来自文档项目的strcspn 示例:stackoverflow.com/documentation/c/1990/strings/10906/…
  • @MarkPlotnick 我想到了strpbrk(),所有的解决方案都有问题,==
  • 编写将字符串拆分为标记的 C 代码总是有些麻烦。如果这是一项作业并且您只需要使用 C,那么这是不可避免的。但是解析算术表达式是很多程序都会做的事情,他们经常使用lexflexyaccbison来生成C代码。这是一个页面,展示了它的简单程度:www-h.eng.cam.ac.uk/help/tpl/languages/flexbison

标签: c


【解决方案1】:

对于您只想解析由两个操作数和一个运算符组成的简单字符串的简单情况,没有“表达式”这可能会起作用

#include <stdio.h>
#include <string.h>

int
main(void)
{
    const char *string = "A > B";
    char lho[100];
    char op[3];
    char rho[100];
    if (sscanf(string, "%99[^=><]%2[=><]%99[^=><]", lho, op, rho) == 3) {
        fprintf(stdout, "left hand operand: %s\n", lho);
        fprintf(stdout, "operator: %s\n", op);
        fprintf(stdout, "right hand operand: %s\n", rho);
    }
    return 0;
}

这绝不是最好的方法,它只是表明你可以使用它。另外,我并没有考虑太多,我编写了代码来向您展示一个可能的解决方案。我真的不喜欢它,我不会用它

【讨论】:

  • 哇,这看起来很聪明! :)
  • 你为什么不用它?
  • 因为它不可靠。我无法立即想到一个明显失败的案例。但我不能相信sscanf()。尽管正如我所说,简单的案例也可以。
【解决方案2】:

这是一个通用的过程:

  1. 对于给定的集合delimiters,使用strstr 检查每个集合是否出现在输入字符串中。作为奖励,我下面的代码允许“双重”条目,例如 &lt;&lt;&gt;;它会检查所有并使用尽可能长的时间。
  2. 确定要使用的最佳分隔符后,您有一个指针指向它的开始。然后你可以
  3. .. 将左侧的所有内容复制到 left 变量中;
  4. .. 将分隔符本身复制到delim 变量中(以保持一致性);和
  5. .. 将分隔符右侧的所有内容复制到 right 变量中。

第 4 点是为了与其他两个变量“保持一致”。您还可以创建一个枚举(LESSEQUALSMORENOT_EQUAL(在我的示例中))并返回它,因为可能性集仅限于这些。

在代码中:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

const char *delimiters[] = {
    "<", ">", "==", "<>", NULL
};

int split_string (const char *input, char **dest_left, char **dest_delim, char **dest_right)
{
    int iterator;
    int best_fit_delim;
    char *ptr;

    /* (optionally) clean whitespace at start */
    while (isspace(*input))
        input++;

    /* look for the longest delimiter we can find */
    best_fit_delim = -1;
    iterator = 0;
    while (delimiters[iterator])
    {
        ptr = strstr (input, delimiters[iterator]);
        if (ptr)
        {
            if (best_fit_delim == -1 || strlen(delimiters[iterator]) > strlen(delimiters[best_fit_delim]))
                best_fit_delim = iterator;
        }
        iterator++;
    }

    /* did we find anything? */
    if (best_fit_delim == -1)
        return 0;

    /* reset ptr to this found one */
    ptr = strstr (input, delimiters[best_fit_delim]);

    /* copy left hand side */
    iterator = ptr - input;
    /* clean whitespace at end */
    while (iterator > 0 && isspace(input[iterator-1]))
        iterator--;
    *dest_left = malloc (iterator + 1);
    memcpy (*dest_left, input, iterator);
    (*dest_left)[iterator] = 0;

    /* the delimiter itself */
    *dest_delim = malloc(strlen(delimiters[best_fit_delim])+1);
    strcpy (*dest_delim, delimiters[best_fit_delim]);

    /* update the pointer to point to *end* of delimiter */
    ptr += strlen(delimiters[best_fit_delim]);
    /* skip whitespace at start */
    while (isspace(*ptr))
        ptr++;

    /* copy right hand side */
    *dest_right = malloc (strlen(ptr) + 1);
    strcpy (*dest_right, ptr);

    return 1;
}

int main (void)
{
    char *source_str = "A <> B";
    char *left, *delim, *right;

    if (!split_string (source_str, &left, &delim, &right))
    {
        printf ("invalid input\n");
    } else
    {
        printf ("left: \"%s\"\n", left);
        printf ("delim: \"%s\"\n", delim);
        printf ("right: \"%s\"\n", right);

        free (left);
        free (delim);
        free (right);
    }
    return 0;
}

结果,对于A &lt;&gt; B,在

left: "A"
delim: "<>"
right: "B"

如果您只需要检查&lt;==&gt; 的列表,代码可以小一些;那么您可以将strchr 用于单个字符(如果找到=,请检查下一个字符)。您也可以忘记best_fit 长度检查,因为只有一个适合。

该代码仅删除比较运算符周围的空格。为了保持一致性,您可能希望删除输入开头和结尾的所有空格;然后,可以通过返回 leftright 长度为 0 的变量来检测无效输入——即,它们仅包含 0 字符串终止符。你仍然需要free那些零长度的字符串。

为了好玩,您可以将"GT","LT","GE","LE" 添加到分隔符中,看看它对A GT BALLEQUALFAULTY&lt;MATCH 等字符串的作用。

【讨论】:

  • 非常感谢,我会接受的。你能看看我的编辑,让我知道你对它的看法吗? (这是不是很糟糕的解决方案?)
  • @Curnelious:假设它可以工作(可以吗,在你的for-loop 中声明了那些leftright?),那么按照我的标准就完全没问题了。当然,它可以写得不那么冗长,也许在风格上也更好。如果它能够始终如一且准确地完成工作,那么它就“足够好”了。通过诸如此类的练习,您可以建立对 C 技能的信心。
猜你喜欢
  • 2014-03-02
  • 1970-01-01
  • 1970-01-01
  • 2013-10-30
  • 2016-07-05
  • 2013-03-03
  • 2018-05-05
  • 2011-03-29
  • 1970-01-01
相关资源
最近更新 更多