C 查找字符串中的字符串分隔符数

C 查找字符串中的字符串分隔符数,c,string,char,C,String,Char,我使用以下方法查找字符串中分隔符的数量: char * string = "xi--len--xia" char * split_on = "--"; size_t len_joined_string = strlen(string); size_t len_split_on = strlen(split_on); size_t num_separators_in_string = 0; for (int i=0; i < len_joined_string; i++) { i

我使用以下方法查找字符串中分隔符的数量:

char * string = "xi--len--xia"
char * split_on = "--";

size_t len_joined_string = strlen(string);
size_t len_split_on = strlen(split_on);
size_t num_separators_in_string = 0;

for (int i=0; i < len_joined_string; i++) {
    if (joined_string_buffer[i] == split_on[0]) {
        int has_match = 1;
        for (int j=1; j < len_split_on; j++) {
            if (joined_string_buffer[i+j] != split_on[j])
                has_match = 0;
        }
        if (has_match)
            num_separators_in_string ++;
    }
}
但是当在一个字符串(字符数组)上而不是在一个单独的
char
上进行拆分时,是否有类似的情况呢?

只是完成了拆分 你可以这样做:

const char * split = "--";
int i;
for(i=0; s[i]; strncmp(&s[i], split, strlen(split)) ? *s++ : i++);
size_t no_splits(const char *str, const char *substr) 
{
    size_t ret = 0;
    const size_t len = strlen(substr);

    for(size_t n = strlen(str) - len; n >= 0; n--)
        if(strncmp(&str[n], substr, len) == 0)
            ret++;

    return ret;
}
请注意,我翻转了
*s++
I++
,因为strncmp在相等时返回0。此外,您可能需要根据处理字符串的方式对其进行修改,如
“xi---len---xia”

让它可读 如果你问我,上面的片段看起来有点笨重和难以理解。如果你问我它是干什么的,我需要一些时间来弄清楚。它的外观是“看看我能做什么”

把它放在函数中 我会把它放在这样一个函数中,为正在阅读你的代码的人隐藏这个可怕的for循环

size_t no_splits(const char *s, const char *split) 
{
    size_t i;
    for(i=0; s[i]; strncmp(&s[i], split, strlen(split)) ? *s++ : i++)
        ; // Put semicolon here to suppress warnings
    return i;
}
使逻辑可读 但是,当您将代码插入到一个命名良好的函数中时,基本上不再需要将代码缩短这么多。为了便于阅读,我将其改写为:

size_t no_splits(const char *s, const char *split) 
{
    size_t i=0;

    // Not only more readable, but also better for performance
    const size_t len=strlen(split);

    while(s[i]) {
        if(strncmp(&s[i], split, len))
            // The only reason to use * in above code was to suppress a warning
            s++; 
        else
            i++;
    }
    return i;
}
请注意,在最后一段代码中,我删除了两个仅用于抑制警告的内容。我并不是说只做事情是为了抑制警告,但当你这么做的时候,这就意味着你应该考虑重新设计你的代码。尽管可以使用不同的for循环,但通常使用for循环的方法是
for(;)
,这与此约定不同,通常是一件坏事。这不仅是因为可读性,也是因为它使优化器更加困难。原因是优化器能够识别常见模式,并有规则对其进行优化

将逻辑更改为更直观的逻辑 事实上,我还认为递增的
s
I
之间的交替非常令人困惑。这是一个(对我来说)更有意义的版本。将while循环更改为:

while(*s) {
    if(strncmp(s, split, len) == 0)
        i++;
    s++;
}
如果确实要压缩,请更改为:

// *s++ is back, but this time with another purpose than suppressing warnings
while(*s++) // Or for(; *s; s++) which I personally think looks better
    if(strncmp(s, split, len) == 0)
        i++;
滥用语法 下面是一个示例,说明如何真正滥用for循环的语法。这是一个矩阵乘法,我用空作为体写的:

// Do NOT do like this!!!
void matrix_multiply(int *A, int *B, int *C, int N)
{
    for(    int i=0,j=0,k=0;
            k++<N ? 1 : ++j<N ? k=1 : ++i<N ? k=1+(j=0) : 0;
            C[i*N + j] = A[i*N + k -1] * B[(k-1)*N + j] + (k==1 ? 0 : C[i*N + j])
    );
}
如果您想让它更快一点,特别是对于long
substr
,您可以这样做:

const char * split = "--";
int i;
for(i=0; s[i]; strncmp(&s[i], split, strlen(split)) ? *s++ : i++);
size_t no_splits(const char *str, const char *substr) 
{
    size_t ret = 0;
    const size_t len = strlen(substr);

    for(size_t n = strlen(str) - len; n >= 0; n--)
        if(strncmp(&str[n], substr, len) == 0)
            ret++;

    return ret;
}

您仍然需要循环,但可以使用
strstr
搜索多字符分隔符或
strchr
搜索单字符分隔符。查找
strstr()
。使用
strtok()
和变体将不起作用;你在很短的时间内问了很多问题——在过去的几个小时里问了6个,昨天又问了5个,或者差不多。它们并不都是坏的——大多数都有一个公认的答案。但你可能应该花更多的时间阅读手册、课本和课程笔记,而不是花更少的时间问这些问题。
size_t no_splits(const char *str, const char *substr) 
{
    size_t ret = 0;
    const size_t len = strlen(substr);

    for(size_t n = strlen(str) - len; n >= 0; n--)
        if(strncmp(&str[n], substr, len) == 0)
            ret++;

    return ret;
}