【问题标题】:Compare two char arrays without CR LF比较两个没有 CR LF 的 char 数组
【发布时间】:2019-04-16 11:39:01
【问题描述】:

我想用下面的函数来比较两个char数组:

if(strcmp((PtrTst->cDatVonCom),szGeraeteAntwort)==0)

现在我的问题是 PtrTst->cDatVonCom[5000]szGeraeteAntwort[255] 不同,整个值看起来有点不同: (摘自日志文件)。

PtrTst->cDatVonCom:

04/16/19 12:53:36 AB A{CR}{LF}
  0  0{CR}{LF}

szGeraeteAntwort:

04/16/19 12:53:36 AB A  0  0{CR}{LF}

我可以检查两个命令(在本例中为 AB A)是否相同? 该命令可以更改,并且必须相同才能通过 if 语句。

更新:

两个字符数组始终存在,我需要检查“szGeraeteAntwort”是否在 PtrTst->cDatVonCom 中。 在 C# 中,我会使用 cDatVonCom.Contains... 或类似的东西来检查是否相同。

【问题讨论】:

  • 其他空白字符呢?
  • 你可以修改数组的内容吗?
  • 真的需要使用strcmp 来执行比较,而不是其他方法吗?就一个电话?
  • 添加到@JohnBollinger,您从cDatVonCom 中提取命令并使用strstr 搜索主数组中的子字符串。如果找到子字符串,strstr 将在主字符串中返回有效指针,否则返回 NULL。
  • @JohnBollinger:这不是必需的,但这是我用我糟糕的 c 技能找到的唯一方法

标签: c parsing newline string-comparison text-processing


【解决方案1】:

您有两个字符串,您希望比较它们的 逻辑 内容,但它们的文字表示可能会有所不同。特别是,可能有 CR/LF 行终止序列插入其中之一或两者中,这对于比较而言并不重要。有很多方法可以解决这类问题,但一种常见的方法是为您的字符串定义一个唯一的规范形式,为该形式准备两个字符串的版本,然后比较结果。在这种情况下,规范形式可能是没有任何 CR 或 LF 字符的形式。

解决此问题的最通用方法是创建字符串的规范化副本。这说明了您无法就地修改字符串的情况。例如:

/*
 * src  - the source string
 * dest - a pointer to the first element of an array that should receive the result.
 * dest_size - the capacity of the destination buffer
 * Returns 0 on success, -1 if the destination array has insufficient capacity
 */
int create_canonical_copy(const char src[], char dest[], size_t dest_size) {
    static const char to_ignore[] = "\r\n";
    const char *start = src;
    size_t dest_length = 0;
    int rval = 0;

    while (*start) {
        size_t segment_length = strcspn(start, to_ignore);

        if (dest_length + segment_length + 1 >= dest_size) {
            rval = -1;
            break;
        }
        memcpy(dest + dest_length, start, segment_length);
        dest_length += segment_length;
        start += segment_length;
        start += strspn(start, to_ignore);
    }
    dest[dest_length] = '\0';

    return rval;
}

你可以这样使用:

char tmp1[255], tmp2[255];

if (create_canonical_copy(PtrTst->cDatVonCom, tmp1, 255) != 0) {
    // COMPARISON FAILS: cDatVonCom has more non-CR/LF data than szGeraeteAntwort
    // can even accommodate
    return -1;
} else if (create_canonical_copy(szGeraeteAntwort, tmp2, 255) != 0) {
    // should not happen, given that szGeraeteAntwort's capacity is the same as tmp2's.
    // If it does, then szGeraeteAntwort must not be properly terminated
    assert(0);
    return -1;
} else {
    return strcmp(tmp1, tmp2);
}

这假设您仅比较字符串是否相等。如果您也针对 order 比较它们,那么您仍然可以使用这种方法,但您需要更加小心地规范化尽可能多的数据,并正确处理数据太大的情况。

【讨论】:

  • 很好地使用strcspn(), strspn()
  • 我认为将strcspn(), strspn()strncmp() 一起使用可以消除对副本的需求。但现在没时间回答。
  • 我考虑过,@chux。我同意这应该是可能的,但是要正确处理一般情况需要仔细记账。另外,我想将 OP 介绍给规范形式的概念,因为即使他们不将其用于 this 目的,在您的工具箱中拥有它也是一件有用的事情。
  • 谢谢@xing,已修复。我写的代码有点仓促。
【解决方案2】:

可以使用在跳过某些字符的同时比较字符串的函数。

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

int strcmpskip ( char *match, char *against, char *skip) {
    if ( ! match && ! against) { //both are NULL
        return 0;
    }
    if ( ! match || ! against) {//one is NULL
        return 1;
    }
    while ( *match && *against) {//both are not zero
        while ( skip && strchr ( skip, *match)) {//skip not NULL and *match is in skip
            match++;
            if ( ! *match) {//zero
                break;
            }
        }
        while ( skip && strchr ( skip, *against)) {//skip not NULL and *against is in skip
            against++;
            if ( ! *against) {//zero
                break;
            }
        }
        if ( *match != *against) {
            break;
        }
        if ( *match) {//not zero
            match++;
        }
        if ( *against) {//not zero
            against++;
        }
    }
    return *match - *against;
}

int main( void) {
    char line[] = "04/16/19 12:53:36 AB A\r\n 0  0\r\n";
    char text[] = "04/16/19 12:53:36 AB A 0  0\r\n";
    char ignore[] = "\n\r";

    if ( strcmpskip ( line, text, ignore)) {
        printf ( "do not match\n");
    }
    else {
        printf ( "match\n");
    }

    return 0;
}

【讨论】:

    【解决方案3】:

    您可以做几件事;这里有两个:

    1. 解析两个字符串(例如,使用scanf() 或更花哨的东西),并在解析过程中忽略换行符。现在您将拥有不同的字段(或表明其中一行无法正确解析,无论如何这是一个错误)。然后您可以比较命令。
    2. 在这两个字符串上使用regular expression 匹配器,只获取命令而忽略其他所有内容(本质上将 CR 和 LF 视为换行符),然后比较命令。当然,您需要编写适当的正则表达式。

    【讨论】:

    • 感谢您的回答,我有一个问题:您会为两个 char 数组制作 fget 吗?
    • 好的,谢谢。我有两个 char 数组,在一个中我可以设置一个我期望在另一个 char 数组中的答案(带有 scale anwsers 的 scale 命令)。因此我需要检查。我可以在 if(...) 语句中使用 fgets() 吗?我现在不确定..
    • 抱歉,我说错了。 fgets() 用于从文件中读取。它是scanf(),可用于解析。此外,这可能需要一个小函数,而不是单行代码。
    • 好的,但是当我看到它时,scanf 是用于输入内容吗?两个 char 数组始终存在,它们只需要检查是否相同。你不能进入那里的东西。对不起。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-07
    • 1970-01-01
    • 2015-03-31
    相关资源
    最近更新 更多