【问题标题】:Merge two specific columns from a line in C language在 C 语言中合并一行中的两个特定列
【发布时间】:2018-06-13 13:47:38
【问题描述】:

我想在 C 语言中合并一行中的两个特定列。该行就像“hello world hello world”。它由一些单词和一些空格组成。以下是我的代码。在这个函数中,c1 和 c2 代表列的编号,数组 key 是合并后的字符串。但是不好跑。

char *LinetoKey(char *line, int c1, int c2, char key[COLSIZE]){
    char *col2 = (char *)malloc(sizeof(char));
    while (*line != '\0' && isspace(*line) )
        line++;
    while(*line != '\0' && c1 != 0){
        if(isspace(*line)){
            while(*line != '\0' && isspace(*line))
                line++;
            c1--;
            c2--;
        }else
            line++;
    }
    while (*line != '\0' && *line != '\n' && (isspace(*line)==0))
        *key++ = *line++;
    *key = '\0';
    while(*line != '\0' && c2 != 0){
        if(isspace(*line)){
            while(*line != '\0' && isspace(*line))
                line++;
            c2--;
        }else
            line++;
    }
    while (*line != '\0' && *line != '\n' && isspace(*line)==0)
        *col2++ = *line++;
    *col2 = '\0';
    strcat(key,col2);
    return key;
}

【问题讨论】:

  • 我建议编写一个自己的函数,只需在行内返回一个字符串指针和一个长度,即可将您的行拆分为单个标记(列)。然后在你的 LinetoKey 实现中使用这个函数。这降低了代码的复杂性。分别测试和组合这两个函数。
  • 使用(char *)malloc(sizeof(char));,您只会为单个字符分配内存——因此当您向col2 写入多个字符时,您将写入未分配的内存。
  • “这条线就像“hello world hello world””预期的输出是什么?
  • @ZDF: 如果c10 并且c33 我假设预期的输出是"helloworld"

标签: c string merge line multiple-columns


【解决方案1】:

这是使用strtok() 的可能解决方案。它可以处理任意数量的列(如果需要,增加buf 的大小),并且如果列的顺序颠倒(即c1 > c2),它仍然可以工作。该函数在成功(令牌成功合并)时返回1,否则返回0

请注意,strtok() 修改了它的参数 - 所以我已将 input 复制到临时缓冲区 char buf[64]

/*
 * Merge space-separated 'tokens' in a string.
 * Columns are zero-indexed.
 *
 * Return: 1 on success, 0 on failure
 */
int merge_cols(char *input, int c1, int c2, char *dest) {
    char buf[64];
    int col = 0;
    char *tok = NULL, *first = NULL, *second = NULL, *tmp = NULL;

    if (c1 == c2) {
        fprintf(stderr, "Columns can not be the same !");
        return 0;
    }

    if (strlen(input) > sizeof(buf) - 1) return 0;

    /*
     * strtok() is _destructive_, so copy the input to
     * a buffer.
     */
    strcpy(buf, input);

    tok = strtok(buf, " ");
    while (tok) {
        if (col == c1 || col == c2) {
            if (!first)
                first = tok;
            else if (first && !second)
                second = tok;
        }
        if (first && second) break;
        tok = strtok(NULL, " ");
        col++;
    }
    // In case order of columns is swapped ...
    if (c1 > c2) {
        tmp = second;
        second = first;
        first = tmp;
    }
    if (first) strcpy(dest, first);
    if (second) strcat(dest, second);

    return first && second;
}

示例用法:

char *input = "one two three four five six seven eight";
char dest[128];

// The columns can be reversed ...
int merged = merge_cols(input, 7, 1, dest);
if (merged)
    puts(dest);

另请注意,在使用 strtok() 时使用不同的分隔符非常容易 - 因此,如果您想使用逗号或制表符分隔的输入而不是空格,您只需在调用时更改第二个参数。

【讨论】:

  • 不传递c1c2,为什么不传递一个包含c1, c2的数组呢?如果您只关心 2 列,那么没关系,但如果您感兴趣的列数可能会有所不同,那么传递一个数组,该数组中的元素数将允许您循环遍历数组在没有硬编码测试的情况下仅对 2 进行列号比较。
  • @DavidC.Rankin:这是一个尝试:link。 (未在此处发布,因为 OP 似乎想要更具体的内容。)
【解决方案2】:

目前尚不清楚您要做什么。如果 David Collins 建议的是您正在寻找的内容 - 按单词索引进行单词连接 - 这是一个起点 (demo):

  • 您的函数必须尽量减少字符串遍历次数。为了解决这个问题,下面的代码使用了char** 而不是char*(类似于“字符流”)。
  • 函数必须能够在实际连接之前计算结果将包含的字符数,以便能够在免费存储中分配目标字符串。如果catwords 以空目标调用,它只计算结果字符串的长度。

关于实际实现,您必须逐字遍历字符串,并决定是复制还是跳过该单词。以下功能见以下代码:

  • nextword - 跳过空白,直到找到非空白字符。
  • copyword - 如果目标有效则复制当前单词,否则跳过它。它返回复制/跳过的字符数。


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

void nextword( const char** ps )
{
  while ( **ps && isspace( **ps ) )
    ++*ps;
}

int copyword( char** const pd, const char** ps )
{
  // remember the starting point
  const char* b = *ps;

  // actual copy
  if ( pd && *pd ) while ( **ps && !isspace( **ps ) )
    *( *pd )++ = *( *ps )++;

  // skip the word (no destination)
  else while ( **ps && !isspace( **ps ) )
    ( *ps )++;

  // return the length
  return *ps - b;
}

int catwords( char* d, const char* s, const int* c )
{
  int len = 0;
  int iw = 0;
  int ic = 0;
  const char** ps = &s;
  char** pd = &d;

  for ( nextword( ps ); **ps && c[ ic ] > -1; nextword( ps ), ++iw )
    if ( iw == c[ ic ] )
    {
      len += copyword( pd, ps );
      ++ic;
    }
    else
    {
      copyword( 0, ps ); // just skip the current word
    }

  if ( d )
    **pd = '\0';

  return len;
}

int main()
{
  // static buffer test
  {
    char d[ 1024 ];
    int t[] = { 0, 3, -1 };
    catwords( d, "Hello world. Hello world!", t );
    puts( d );
  }

  // dynamic buffer test
  {
    const char* s = "The greatness of a man is not in how much wealth he acquires, but in his integrity and his ability to affect those around him positively.";
    int t[] = { 1, 5, 16, -1 };
    int dstcharcount = catwords( 0, s, t ) + 1;
    char* d = (char*)malloc( dstcharcount * sizeof( char ) );
    catwords( d, s, t );
    puts( d );
    free( d );
  }

  return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多