C 基于文件中的密钥进行排序

C 基于文件中的密钥进行排序,c,file,unix,sorting,C,File,Unix,Sorting,我需要对从类似以下文件中读取的内容进行排序: Key: 2 rec:1 2 3 4 5 6 ... Key: 3 rec:7 8 9 10 11 ... Key: 1 rec:A B C D E F ... 变成 Key: 1 rec:A B C D E F ... Key: 2 rec:1 2 3 4 5 6 ... Key: 3 rec:7 8 9 10 11 ... 如果我们在一个键的rec(记录)中有未排序的内容,它将保持不变!因为排序是基于键的。我想使用C中定义的qsort()进行

我需要对从类似以下文件中读取的内容进行排序:

Key: 2 rec:1 2 3 4 5 6 ...
Key: 3 rec:7 8 9 10 11 ...
Key: 1 rec:A B C D E F ...
变成

Key: 1 rec:A B C D E F ...
Key: 2 rec:1 2 3 4 5 6 ...
Key: 3 rec:7 8 9 10 11 ...
如果我们在一个键的rec(记录)中有未排序的内容,它将保持不变!因为排序是基于键的。我想使用C中定义的qsort()进行排序。我有一个想法,可以使用strtok将从文件中读取的每一行拆分为可管理的数组,但我不知道这是否是找到键号的最佳方法,以便使用C库中的qsort对它们进行排序

注意:输入文件的每一行都包含一个键,如key:1 rec:A B C D E F。。。
此外,我们不会对键内的记录进行排序。

如果键的长度不相同,则应避免使用
strncmp
,逐行读取,然后使用循环从第[5]行到下一个空格获取键值(或者使用带空格分隔符的
strtok

重复此操作直到
EOF
。在数组或列表中存储键值

下一个排序数组或列表

现在使用
strstr
从文件中的排序数组中找到Key的值,并将匹配的行复制到新文件中。在使用
strstr
之前,请将键转换为字符串


如果要避免添加到新文件中,需要使用
fseek
在行之间移动文件指针并修改行。

要在c中执行此操作,请使用,您可以获得一种正则表达式来提取所需的整数:

int comp(const void *str1, const void *str2) {
    char *a = *(char **)str1, *b = *(char **)str2;
    int key1, key2;
    sscanf(a, "%*s%d", &key1);
    sscanf(b, "%*s%d", &key2);
    return key1-key2;
}

//Call the function qsort like so
qsort(/*char **/lines, /*int*/numElements, /*unsigned*/ sizeof (char*), comp);
<>不知道如何在C++中使用库,但是<代码> sSCANF仍然有效。c++11中的完整工作示例:

#include <iostream>
#include <cstdio>
#include <deque>
#include <string>
#include <algorithm>

int main() {

    //Using fstream, read in each line of the file into a string using getline(...)
    std::deque<std::string> lines = {
        "Key: 2 rec:1 2 3 4 5 6",
        "Key: 3 rec:7 8 9 10 11",
        "Key: 1 rec:A B C D E F",
        "Key: 4 rec:1 2 3 4 5 6"
    }; //Store each in a deque object

    //using std::sort
    std::sort(lines.begin(), lines.end(), []( const std::string &str1, const std::string &str2 ) {
        int key1, key2;
        sscanf(str1.c_str(), "%*s%d", &key1);
        sscanf(str2.c_str(), "%*s%d", &key2);
        return (key1 < key2);
    });


    for (auto sortedkeys: lines)
        std::cout << sortedkeys << "\n";
    return 0;
}
#包括
#包括
#包括
#包括
#包括
int main(){
//使用fstream,使用getline(…)将文件的每一行读入字符串
std::deque行={
“密钥:2记录:1 2 3 4 5 6”,
“密钥:3记录:7 8 9 10 11”,
“密钥:1记录:A B C D E F”,
“密钥:4记录:1 2 3 4 5 6”
};//将每个存储在deque对象中
//使用std::sort
std::sort(lines.begin()、lines.end()、[](常量std::string和str1、常量std::string和str2){
int键1,键2;
sscanf(str1.c_str(),“%*s%d”和键1);
sscanf(str2.c_str(),“%*s%d”和键2);
返回(键1<键2);
});
用于(自动分拣机:行)

如果你必须写C,它不需要那么长或复杂。如果你略过错误检查,你可以简化它

#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

extern void err_exit(const char *fmt, ...);

typedef struct data
{
    char *line;
    int   key;
} data;

static int cmp_data(const void *v1, const void *v2)
{
    const data *d1 = v1;
    const data *d2 = v2;
    if (d1->key < d2->key)
        return -1;
    else if (d1->key > d2->key)
        return +1;
    else
        return 0;
}

int main(void)
{
    char buffer[4096];
    data *array = 0;
    size_t array_len = 0;
    size_t array_max = 0;

    while (fgets(buffer, sizeof(buffer), stdin) != 0)
    {
        if (array_len >= array_max)
        {
            size_t new_size = (array_max + 2) * 2;
            void *space = realloc(array, new_size * sizeof(data));
            if (space == 0)
                err_exit("Out of memory (1)");
            array = space;
            array_max = new_size;
        }
        array[array_len].line = strdup(buffer);
        if (array[array_len].line == 0)
            err_exit("Out of memory (2)");
        if (sscanf(array[array_len].line, "%*s %d", &array[array_len].key) != 1)
            err_exit("Format error - no number in right place in: %.20s...\n",
                     array[array_len].line);
        //printf("%3zu:%.10d: %s", array_len, array[array_len].key,
        //       array[array_len].line);
        array_len++;
    }

    qsort(array, array_len, sizeof(data), cmp_data);

    for (size_t i = 0; i < array_len; i++)
        fputs(array[i].line, stdout);

    return 0;
}

void err_exit(const char *fmt, ...)
{
    int errnum = errno;
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    if (errnum != 0)
        fprintf(stderr, " (%d: %s)", errnum, strerror(errnum));
    putc('\n', stderr);
    exit(EXIT_FAILURE);
}

然后,您决定如果
ifp
不为null,则将其用于输入-否则打开由
i_file
指定的文件。类似地,对于输出:如果
ofp
不为null,则使用它-否则,打开由
o_file
指定的文件。对
main()
sort_file()主体的更改
是微不足道的。

我建议查看unix中的
sort
命令。您的问题有点不清楚,但是
sort-nyourfile>sortedfile
可能会执行您想要的操作(对文件进行数字排序)关键部分的长度是否相等?如果是,您可以编写一个比较函数,根据strncmp()对每行的头进行排序(并使用指针魔术跳过“key:”)。您是否试图避免将所有行加载到内存中?@n0741337我不一定这样认为。下面是一个排序程序输入文件的示例!还有什么其他方法可以用于提取键的值并根据其值对文件的每行进行排序?请检查
sort-k2,2-n
。否则,因为它们不是固定长度的部分,您需要自己识别前两个空格。为此,您可以使用指针而不是strtok()正在为您的比较函数进行排序。如果您的任务是对数据进行排序,请使用
sort-k2,2n
sort-k2,2-n
,然后您就到家了。如果您的任务是编写C代码,那么您前面还有一些工作要做……数据集是否足够小,可以放入内存中,或者您是否需要担心外部排序(尽可能多地读取内存中的数据,对其进行排序,将其写入临时文件,重复直到所有数据都已读取,然后合并所有文件)?如果可以将所有数据都放入内存中,这不会太痛苦。最大的数字可以放入32位
int
(一个有符号的数字,除非我误读了数据)。[…继续…]我同意你的回答,我们应该找到第[5]行,因为在“key:1804289383”180…中,从第[5]行开始。如何从文件中取出行并将它们放入字符串中?我们在C中有任何这样的get_line预定义函数吗?我想如果我使用第[5]行方法,我基本上不需要使用strtok,对吗?定义最大行。#定义
MAX\u行+1的最大行长
。声明一个字符串
char行[MAX\u行]
。首先在
fopen()的帮助下以r+模式打开文件。
ex:
fp=fopen(“文件”,“r+”)
,然后使用
fgets()
ex:
fgets:
(line,MAX_line,fp)
从文件中读取行。使用字符串行。如果使用第[5]行,则不需要使用strok下一个空间。C中的这个程序是什么?我不应该使用C++。我知道如何使用Q排序和如何在C中编写比较函数。我主要需要知道如何在键之后精确地到达数字:以及如何根据键对所有行排序。谢谢。我已经向你们展示了比较函数应该如何使用。看起来,你现在所要做的就是用你正在读取的文件中的所有行填充一个数组,并计算读取的行数;然后用我显示的方式调用qsort。在上面的代码中,应该很简单,你在哪里处理文件指针和文件名?这种排序需要从文件中读取数据,然后进行一些中间处理ate计算,然后再次写回文件。请告诉我您是否知道用C处理文件的版本(或可以修改您的版本)。谢谢。代码读取自
stdin
(参见
fgets()
行)并写入
stdout
(参见
fputs()
行)。如果要读取文件,必须
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static void sort_file(const char *i_file, const char *o_file);

int main(int argc, char **argv)
{
    if (argc > 1)
    {
        for (int i = 1; i < argc; i++)
            sort_file(argv[i], argv[i]);
    }
    else
        sort_file("/dev/stdin", "/dev/stdout");
    return 0;
}

typedef struct data
{
    char *line;
    int   key;
} data;

static int cmp_data(const void *v1, const void *v2)
{
    const data *d1 = v1;
    const data *d2 = v2;
    if (d1->key < d2->key)
        return -1;
    else if (d1->key > d2->key)
        return +1;
    else
        return 0;
}

static void err_exit(const char *fmt, ...)
{
    int errnum = errno;
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    if (errnum != 0)
        fprintf(stderr, " (%d: %s)", errnum, strerror(errnum));
    putc('\n', stderr);
    exit(EXIT_FAILURE);
}

void sort_file(const char *i_file, const char *o_file)
{
    char buffer[4096];
    data *array = 0;
    size_t array_len = 0;
    size_t array_max = 0;

    FILE *i_fp = fopen(i_file, "r");
    if (i_fp == 0)
        err_exit("Failed to open file %s for reading", i_file);

    while (fgets(buffer, sizeof(buffer), i_fp) != 0)
    {
        if (array_len >= array_max)
        {
            size_t new_size = (array_max + 2) * 2;
            void *space = realloc(array, new_size * sizeof(data));
            if (space == 0)
                err_exit("Out of memory (1)");
            array = space;
            array_max = new_size;
        }
        array[array_len].line = strdup(buffer);
        if (array[array_len].line == 0)
            err_exit("Out of memory (2)");
        if (sscanf(array[array_len].line, "%*s %d", &array[array_len].key) != 1)
            err_exit("Format error - no number in right place in: %.20s...\n",
                     array[array_len].line);
        //printf("%3zu:%.10d: %s", array_len, array[array_len].key,
        //       array[array_len].line);
        array_len++;
    }
    fclose(i_fp);

    qsort(array, array_len, sizeof(data), cmp_data);

    FILE *o_fp = fopen(o_file, "w");
    if (o_fp == 0)
        err_exit("Failed to open file %s for writing", o_file);
    for (size_t i = 0; i < array_len; i++)
        fputs(array[i].line, o_fp);
    fclose(o_fp);
}
void sort_file(const char *i_file, FILE *ifp, const char *o_file, FILE *ofp);