【问题标题】:How to strip newlines from a char-array?如何从字符数组中删除换行符?
【发布时间】:2023-03-31 06:35:01
【问题描述】:

我已使用此函数将文件的内容放入字符数组中:

void Read::readFile(){
FILE * fp = fopen(this->filename,"rt");
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *pData = new char[size + 1];
fread(pData, sizeof(char), size, fp);
fclose(fp);
this->data = pData;
}

现在我想从字符数组中删除所有行尾。 在不先将字符数组转换为字符串的情况下如何做到这一点?

顺便说一句。这是我们不允许使用字符串库的家庭作业的一部分。

【问题讨论】:

  • 为什么要使用C函数读取文件,为什么不使用字符串类来处理字符串数据?
  • 你是什么意思“剥离”?你想将整个数组复制到其他地方减去换行符还是用其他字符替换换行符?
  • @Duck 我认为 OP 不想进行复制操作
  • @Duck 可以说也有人会问,这是用 c++ 标记的吗?
  • @Hedge:不,不要删除 C++ 标签。这不是有效的 C(它使用 C++ 范围运算符 ::newthis 关键字)。

标签: c++ pointers char


【解决方案1】:
#include <algorithm>
size = std::remove(pData, pData + size, '\n') - pData;
pData[size] = 0; // optional

对于一些 C++11 lambda 的乐趣:

#include <algorithm>
size = std::remove_if(pData, pData + size, [](char c) { return c == '\n'; }) - pData;
pData[size] = 0; // optional

【讨论】:

  • 我的想法完全正确。简单、现代、有效、高效。
  • 单班轮解决方案总是最好的 IMO +1。
  • 击败其他人,因为它本质上也是单线。
  • 很好的解决方案,但是 size 的类型是 long 而不是 char *
  • 如果换行符使用\r\n而不是裸\n怎么办?
【解决方案2】:

最简单的方法是制作一个与原始数组大小相同的第二个缓冲区。

int len = size;

char* newBufer = calloc(len,sizeof(char));
int i = 0;
int j = 0;
int nlCount = 0;

for(i=0; i<len; i++) {
  if(pData[i] != '\n') {
    newBuffer[j++] = pData[i];
  } else {
    nlCount++;
  }
}

printf("Finished copying array without newlines. Total newlines removed: %d",nlCount);

这里的额外好处是因为你调用而不是调用你的数组,所有值最初都是零,所以在这种情况下,一旦你完成复制,从 (len-nlCount) 到 (len ) 将全部为零(即:'\0'),因此它会自动以空值结尾,就像字符串一样。完成后不要忘记释放()数组。

【讨论】:

    【解决方案3】:

    就地移除:

    void strip_newlines(char* p) {
        char* q = p;
        while (p != 0 && *p != '\0') {
            if (*p == '\n') {
                p++;
                *q = *p;
            } 
            else {
                *q++ = *p++;
            }
        }
        *q = '\0';
    }
    

    【讨论】:

    • 无用的size 参数......如果有嵌入的NUL怎么办?还会多次无用地复制'\n' 后面的字符,并且不会终止字符串或提供任何查找新大小的方法。
    • 哎呀,当我打算做一个 for 循环时,我把大小放在那里......然后我只切换到指针......将删除。
    • 当while循环完成时不要忘记将换行符添加到字符数组的末尾。
    【解决方案4】:

    类似这样的:

    void Read::readFile()
    { 
        FILE * fp = fopen(this->filename,"rt"); 
        if (fp)
        {
            char *pData = NULL;
    
            fseek(fp, 0, SEEK_END); 
            long size = ftell(fp); 
            if (size != -1L)
            {
                pData = new char[size];
                if (size > 0)
                {
                    fseek(fp, 0, SEEK_SET); 
                    size = fread(pData, sizeof(char), size, fp);
                }
            }
            fclose(fp);
    
            if (size < 0)
            {
                delete[] pData;
                pData = NULL;
            }
            else if (size > 0)
            {
                char *start = pData;
                char *end = start + size;
    
                char *ptr = (char*) memchr(pData, '\n', size);
                while (ptr)
                {
                    int len = 1;
                    if ((ptr > start) && ((*ptr-1) == '\r'))
                    {
                        --ptr;
                        ++len;
                    }
    
                    memmove(ptr, ptr+len, end - (ptr+len));
                    end -= len;
    
                    ptr = (char*) memchr(ptr, '\n', end - ptr);
                }
    
                size = (end - start);
            }
    
            this->data = pData; 
            this->size = size; 
        }
    } 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-01
      • 2016-04-14
      • 2011-10-13
      • 1970-01-01
      • 1970-01-01
      • 2014-05-12
      相关资源
      最近更新 更多