user-0 提问: 没时间了，谢谢！（C语言）对一个文本分别进行第一、二、三关键字查询排序

回复:
user: user-1
content: /**  * @file    demo.c  * @brief     */  #include <stdio.h> #include <stdlib.h> #include <string.h>  struct sort_keys {     char key1[80];     char key2[80];     char key3[80]; };   /**   * @brief 查找下一个键值的位置  *   * @param curr 当前键值的位置  * @param flag 标志 1-中文 0-其他  *   * @return 下一个键值的位置  *   * @note  目前只支持GB2312的字符集，假定汉字的第一位为1  */ const char * get_next_key(const char *curr, int flag) {     const unsigned char *next;      next = (const unsigned char *)curr;     if (flag) {         /* 中文 */         for (; *next; ++next) {             if (*next >= 0x80) {                 return (const char *)next;             }         }     } else {         /* 字符 */         for (; *next; ++next) {             if (*next <= 0x7f) {                 return (const char *)next;             }         }     }      return (const char *)next; }    /**   * @brief 字符串分割为键值  *   * @param line 字符串  * @param keys 键值  *   * @return 0-成功 -1-失败  */ int line_to_keys(const char *line, struct sort_keys *keys) {     const char *curr, *next;     size_t len;     int flag;      if ((unsigned char)line[0] >= 0x80) {         flag = 0;     } else {         flag = 1;     }      curr = line;     next = get_next_key(curr, flag);     flag = !flag;     if (*next == '\0') {         strcpy(keys->key1, curr);         strcpy(keys->key2, "");         strcpy(keys->key3, "");         return -1;     } else {         len = next - curr;         memcpy(keys->key1, curr, len);         keys->key1[len] = '\0';     }      curr = next;     next = get_next_key(curr, flag);     flag = !flag;     if (*next == '\0') {         strcpy(keys->key2, curr);         strcpy(keys->key3, "");     } else {         len = next - curr;         memcpy(keys->key2, curr, len);         keys->key2[len] = '\0';         strcpy(keys->key3, next);     }      return 0; }    /**   * @brief 比较函数(用于qsort)  *   * @param v1   * @param v2  *   * @return   *  * @note 参考qsort的说明  */ int comp_keys(const void *v1, const void *v2) {     int ret;     const struct sort_keys *p1, *p2;      p1 = ( const struct sort_keys *)v1;     p2 = ( const struct sort_keys *)v2;      if (p1->key2[0] == '\0' && p2->key2[0] != '\0')         return +1;     if (p1->key2[0] != '\0' && p2->key2[0] == '\0')         return -1;     if (p1->key2[0] == '\0' && p2->key2[0] == '\0')          return strcmp(p1->key1, p2->key1);     if ((ret = strcmp(p1->key1, p2->key1)) != 0)         return ret;     if ((ret = strcmp(p1->key2, p2->key2)) != 0)         return ret;     return strcmp(p1->key3, p2->key3);  }  struct sort_keys keys[1024];  int main(int argc, char *argv[]) {     int i, n;     size_t len;     char line[240];      printf("%s\n", "=====================");      /* 读入文件并分割成3个键值 */     i = 0;     while (fgets(line, sizeof(line), stdin)) {         if ((len = strlen(line)) > 1) {             line[len - 1] = '\0';         }         line_to_keys(line, &keys[i]);         printf("%s%s%s\n", keys[i].key1, keys[i].key2, keys[i].key3);         ++i;     }      printf("%s\n", "=====================");      /* 排序并输出 */     n = i;     qsort(keys, n, sizeof(struct sort_keys), comp_keys);     for (i = 0; i < n; ++i) {         printf("%s%s%s\n", keys[i].key1, keys[i].key2, keys[i].key3);     }           return 0; }  /* ===================== 铜锣湾2#直流充电柜直流系统故障 铜锣湾预告警信号 铜锣湾2#直流充电柜直流系统故障 小雁溪110kV故障录波装置启动 小北口1#主变低后备保护装置通讯故障 小北口1#主变低后备保护装置通讯故障 小北口2#主变差动保护装置通讯故障 小北口1#主变低后备保护装置通讯故障 开封GPS对时装置报警 小北口2#主变差动保护装置通讯故障 白家冲220kV白格栅二回白07备用 220kV湾铜二回湾223开关谐波监测装置越限报警 110kV湾铜二回湾223开关谐波监测装置越限报警 220kV湾铜二回湾223开关谐波监测装置越限报警 110kV湾铜二回湾223开关谐波监测装置越限报警 ===================== 110kV湾铜二回湾223开关谐波监测装置越限报警 110kV湾铜二回湾223开关谐波监测装置越限报警 220kV湾铜二回湾223开关谐波监测装置越限报警 220kV湾铜二回湾223开关谐波监测装置越限报警 白家冲220kV白格栅二回白07备用 开封GPS对时装置报警 铜锣湾2#直流充电柜直流系统故障 铜锣湾2#直流充电柜直流系统故障 小北口1#主变低后备保护装置通讯故障 小北口1#主变低后备保护装置通讯故障 小北口1#主变低后备保护装置通讯故障 小北口2#主变差动保护装置通讯故障 小北口2#主变差动保护装置通讯故障 小雁溪110kV故障录波装置启动 铜锣湾预告警信号 */

user: user-0
content: 想特别感谢一下赵四老师！！ 昨天去单位报道，现在才有空上来回复，抱歉。 赵老师的程序我下去再好好运行，研究研究下，貌似还有点问题，具体的我还会上来咨询的。谢谢！

user: user-0
content: 引用 11 楼 xucong198949 的回复:你是说像扑克牌一样排序？？先黑红梅方，然后按数字再排？？ 要是这样的话可以用基数排序  没，以汉字开头的就以汉字为第一关键字排序，相同的排在一起；以数字开始的同样你数字为关键字排序

user: user-2
content: 参考10楼思路的改进： //1.txt: //铜锣湾2#直流充电柜直流系统故障 //铜锣湾预告警信号 //铜锣湾2#直流充电柜直流系统故障 //小雁溪110kV故障录波装置启动 //小北口1#主变低后备保护装置通讯故障 //小北口1#主变低后备保护装置通讯故障 //小北口2#主变差动保护装置通讯故障 //小北口1#主变低后备保护装置通讯故障 //开封GPS对时装置报警 //小北口2#主变差动保护装置通讯故障 //白家冲220kV白格栅二回白07备用 //220kV湾铜二回湾223开关谐波监测装置越限报警 //110kV湾沚二回湾223开关谐波监测装置越限报警 //220kV湾铜二回湾223开关谐波监测装置越限报警 //110kV湾沚二回湾223开关谐波监测装置越限报警 // //每行开头以汉字开始的则在遇到数字或字母时截止作为第一关键字，如“铜锣湾、小雁溪、小北口、开封..”， //每行开头以数字字母开始的，如"220kv、110kv"亦为第一关键字； //之后以汉字或数字字母间隔取第二、三、……关键字 //每行按所有关键字排序导出到2.txt //同时将关键字内容导出到3.txt //忽略全部是汉字的行 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <search.h> #define MAXC 1024  //每行最多字节数 #define MAXL 20000 //最多行数 #define MAXF 20    //每行最多关键字数 #define MAXW 80    //每个关键字最多字节数 #define MAXK 5000  //最多总关键字数 char *ss; int sn; char *kk; unsigned int kn; FILE *f; char ln[MAXC]; char kw[MAXW]; char *p,*q; int i,j,k,L; int isaschz(char *s,int i) {//返回:0asc|1hzq|2hzw     static char *ls=NULL;     static int i1;     static int lr;     int ii;      if (s==ls && i1==i-1) { //      ls=s;         ii=i;         if (0==ls[ii]) {lr=0;return lr;}         switch (lr) {         case 0:             if (ls[ii]<0) lr=1;         break;         case 1:             if (ls[ii]<0 || 0x40<=ls[ii]) lr=2;         break;         case 2:             if (ls[ii]<0) lr=1;             else lr=0;         break;         }         i1=ii;         return lr;     } else {         ls=s;         ii=0;         lr=0;         while (1) {             if (0==ls[ii]) break;             switch (lr) {             case 0:                 if (ls[ii]<0) lr=1;             break;             case 1:                 if (ls[ii]<0 || 0x40<=ls[ii]) lr=2;             break;             case 2:                 if (ls[ii]<0) lr=1;                 else lr=0;             break;             }             if (ii==i) {                 i1=ii;                 return lr;             }             ii++;         }         return lr;     }  } int cmpk(const void *arg1, const void *arg2 ) {     return strcmp((char*)arg1,(char*)arg2); } int cmp(const void *arg1, const void *arg2 ) {     int r,n;     char *p1,*p2;      p1=(char *)arg1;     p2=(char *)arg2;     for (n=0;n<MAXF;n++) {         r=strcmp(p1+n*MAXW,p2+n*MAXW);         if (r) return r;     }     return 0; } int main() {     ss=(char *)calloc(MAXW*MAXF*MAXL,1);     if (NULL==ss) return 1;     kk=(char *)calloc(MAXW*MAXK,1);     if (NULL==kk) {free(ss);return 2;}     f=fopen("1.txt","r");     if (NULL==f) {printf("Can not open file 1.txt!\n");free(kk);free(ss);return 3;}     i=0;     kn=0;     while (1) {         if (NULL==fgets(ln,MAXC,f)) break;         L=strlen(ln)-1;         ln[L]=0;//去掉行尾的'\n'         for (j=0;j<L;j++) if (isaschz(ln,j)==0) break;         if (j<L) {//不全是汉字             k=0;             if (ln[0]>0) {//数字字母开头                 p=ln;                 while (1) {                     j=0;                     while (1) {                         if (isaschz(p,j)) break;                         j++;                     }                     strncpy(ss+i*MAXW*MAXF+k*MAXW,p,__min(MAXW-1,j));                     strncpy(kw                  ,p,__min(MAXW-1,j));kw[__min(MAXW-1,j)]=0;                     _lsearch(kw,kk,&kn,MAXW,cmpk);                     k++;                     if (k>=MAXF) break;                     if (0==p[j]) break;                     p+=j;                     j=0;                     while (1) {                         if (isaschz(p,j)==0) break;                         j++;                     }                     strncpy(ss+i*MAXW*MAXF+k*MAXW,p,__min(MAXW-1,j));                     strncpy(kw                  ,p,__min(MAXW-1,j));kw[__min(MAXW-1,j)]=0;                     _lsearch(kw,kk,&kn,MAXW,cmpk);                     k++;                     if (k>=MAXF) break;                     if (0==p[j]) break;                     p+=j;                 }             } else {//汉字开头                 p=ln;                 while (1) {                     j=0;                     while (1) {                         if (isaschz(p,j)==0) break;                         j++;                     }                     strncpy(ss+i*MAXW*MAXF+k*MAXW,p,__min(MAXW-1,j));                     strncpy(kw                  ,p,__min(MAXW-1,j));kw[__min(MAXW-1,j)]=0;                     _lsearch(kw,kk,&kn,MAXW,cmpk);                     k++;                     if (k>=MAXF) break;                     if (0==p[j]) break;                     p+=j;                     j=0;                     while (1) {                         if (isaschz(p,j)) break;                         j++;                     }                     strncpy(ss+i*MAXW*MAXF+k*MAXW,p,__min(MAXW-1,j));                     strncpy(kw                  ,p,__min(MAXW-1,j));kw[__min(MAXW-1,j)]=0;                     _lsearch(kw,kk,&kn,MAXW,cmpk);                     k++;                     if (k>=MAXF) break;                     if (0==p[j]) break;                     p+=j;                 }             }             i++;             if (i>=MAXL) {printf("Warning:>%d lines is ignored.\n",MAXL); break;}         }     }     fclose(f);     sn=i;     qsort(ss,sn,MAXW*MAXF,cmp);     f=fopen("2.txt","w");     for (i=0;i<sn;i++) {         k=0;         while (1) {             if (0==(ss+i*MAXW*MAXF+k*MAXW)[0]) break;             fprintf(f,"%s",ss+i*MAXW*MAXF+k*MAXW);             k++;         }         fprintf(f,"\n");     }     fclose(f);     f=fopen("3.txt","w");     for (i=0;i<(int)kn;i++) {         fprintf(f,"%s\n",kk+i*MAXW);     }     fclose(f);     free(kk);     free(ss);     return 0; } //2.txt: //110kV湾沚二回湾223开关谐波监测装置越限报警 //110kV湾沚二回湾223开关谐波监测装置越限报警 //220kV湾铜二回湾223开关谐波监测装置越限报警 //220kV湾铜二回湾223开关谐波监测装置越限报警 //白家冲220kV白格栅二回白07备用 //开封GPS对时装置报警 //铜锣湾2#直流充电柜直流系统故障 //铜锣湾2#直流充电柜直流系统故障 //小北口1#主变低后备保护装置通讯故障 //小北口1#主变低后备保护装置通讯故障 //小北口1#主变低后备保护装置通讯故障 //小北口2#主变差动保护装置通讯故障 //小北口2#主变差动保护装置通讯故障 //小雁溪110kV故障录波装置启动 // //3.txt: //铜锣湾 //2# //直流充电柜直流系统故障 //小雁溪 //110kV //故障录波装置启动 //小北口 //1# //主变低后备保护装置通讯故障 //主变差动保护装置通讯故障 //开封 //GPS //对时装置报警 //白家冲 //220kV //白格栅二回白 //07 //备用 //湾铜二回湾 //223 //开关谐波监测装置越限报警 //湾沚二回湾 //

user: user-3
content: 你是说像扑克牌一样排序？？先黑红梅方，然后按数字再排？？ 要是这样的话可以用基数排序

user: user-2
content: 以上3.txt最后三行是因为 湾沚二回湾 中的“沚”字的后半字节为0x61被误判为'b'。  想要纠正此问题，请相应修改判断该字节是否为数字字母或汉字的语句 if (p[j]>=0) break; 和 if (p[j]<=0) break;  思路为从本行的第一个字节开始记录当前字节为： 汉字的前半个字节 汉字的后半个字节 数字或字母 三者之一。 参考下面：    //GBK汉字内码范围（不包括A1xx～A9xx的标点符号英文字母特殊符号等）    //区码  ,位码    //81-A0 ,40-7E 80-FE    //AA-AF ,40-7E 80-A0    //B0-D6 ,40-7E 80-FE    //D7    ,40-7E 80-F9    //D8-F7 ,40-7E 80-FE    //F8-FE ,40-7E 80-A0

user: user-2
content: 这个世界上最大的差别和最远的距离都存在于“说”和“做”之间。  //1.txt: //铜锣湾2#直流充电柜直流系统故障 //铜锣湾预告警信号 //铜锣湾2#直流充电柜直流系统故障 //小雁溪110kV故障录波装置启动 //小北口1#主变低后备保护装置通讯故障 //小北口1#主变低后备保护装置通讯故障 //小北口2#主变差动保护装置通讯故障 //小北口1#主变低后备保护装置通讯故障 //开封GPS对时装置报警 //小北口2#主变差动保护装置通讯故障 //白家冲220kV白格栅二回白07备用 //220kV湾铜二回湾223开关谐波监测装置越限报警 //110kV湾沚二回湾223开关谐波监测装置越限报警 //220kV湾铜二回湾223开关谐波监测装置越限报警 //110kV湾沚二回湾223开关谐波监测装置越限报警 // //每行开头以汉字开始的则在遇到数字或字母时截止作为第一关键字，如“铜锣湾、小雁溪、小北口、开封..”， //每行开头以数字字母开始的，如"220kv、110kv"亦为第一关键字； //之后以汉字或数字字母间隔取第二、三、……关键字 //每行按所有关键字排序导出到2.txt //同时将关键字内容导出到3.txt //忽略全部是汉字的行 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <search.h> #define MAXC 1024  //每行最多字节数 #define MAXL 20000 //最多行数 #define MAXF 20    //每行最多关键字数 #define MAXW 80    //每个关键字最多字节数 #define MAXK 5000  //最多总关键字数 char *ss; int sn; char *kk; unsigned int kn; FILE *f; char ln[MAXC]; char kw[MAXW]; char *p,*q; int i,j,k,L; int cmpk(const void *arg1, const void *arg2 ) {     return strcmp((char*)arg1,(char*)arg2); } int cmp(const void *arg1, const void *arg2 ) {     int r,n;     char *p1,*p2;      p1=(char *)arg1;     p2=(char *)arg2;     for (n=0;n<MAXF;n++) {         r=strcmp(p1+n*MAXW,p2+n*MAXW);         if (r) return r;     }     return 0; } int main() {     ss=(char *)calloc(MAXW*MAXF*MAXL,1);     if (NULL==ss) return 1;     kk=(char *)calloc(MAXW*MAXK,1);     if (NULL==kk) {free(ss);return 2;}     f=fopen("1.txt","r");     if (NULL==f) {printf("Can not open file 1.txt!\n");free(kk);free(ss);return 3;}     i=0;     kn=0;     while (1) {         if (NULL==fgets(ln,MAXC,f)) break;         L=strlen(ln)-1;         ln[L]=0;//去掉行尾的'\n'         for (j=0;j<L;j++) if (ln[j]>0) break;         if (j<L) {//不全是汉字             k=0;             if (ln[0]>0) {//数字字母开头                 p=ln;                 while (1) {                     j=0;                     while (1) {                         if (p[j]<=0) break;                         j++;                     }                     strncpy(ss+i*MAXW*MAXF+k*MAXW,p,__min(MAXW-1,j));                     strncpy(kw                  ,p,__min(MAXW-1,j));kw[__min(MAXW-1,j)]=0;                     _lsearch(kw,kk,&kn,MAXW,cmpk);                     k++;                     if (k>=MAXF) break;                     if (0==p[j]) break;                     p+=j;                     j=0;                     while (1) {                         if (p[j]>=0) break;                         j++;                     }                     strncpy(ss+i*MAXW*MAXF+k*MAXW,p,__min(MAXW-1,j));                     strncpy(kw                  ,p,__min(MAXW-1,j));kw[__min(MAXW-1,j)]=0;                     _lsearch(kw,kk,&kn,MAXW,cmpk);                     k++;                     if (k>=MAXF) break;                     if (0==p[j]) break; 					p+=j;                 }             } else {//汉字开头                 p=ln;                 while (1) {                     j=0;                     while (1) {                         if (p[j]>=0) break;                         j++;                     }                     strncpy(ss+i*MAXW*MAXF+k*MAXW,p,__min(MAXW-1,j));                     strncpy(kw                  ,p,__min(MAXW-1,j));kw[__min(MAXW-1,j)]=0;                     _lsearch(kw,kk,&kn,MAXW,cmpk);                     k++;                     if (k>=MAXF) break;                     if (0==p[j]) break;                     p+=j;                     j=0;                     while (1) {                         if (p[j]<=0) break;                         j++;                     }                     strncpy(ss+i*MAXW*MAXF+k*MAXW,p,__min(MAXW-1,j));                     strncpy(kw                  ,p,__min(MAXW-1,j));kw[__min(MAXW-1,j)]=0;                     _lsearch(kw,kk,&kn,MAXW,cmpk);                     k++;                     if (k>=MAXF) break;                     if (0==p[j]) break;                     p+=j;                 }             }             i++;             if (i>=MAXL) {printf("Warning:>%d lines is ignored.\n",MAXL); break;}         }     }     fclose(f);     sn=i;     qsort(ss,sn,MAXW*MAXF,cmp);     f=fopen("2.txt","w");     for (i=0;i<sn;i++) {         k=0;         while (1) {             if (0==(ss+i*MAXW*MAXF+k*MAXW)[0]) break;             fprintf(f,"%s",ss+i*MAXW*MAXF+k*MAXW);             k++;         }         fprintf(f,"\n");     }     fclose(f);     f=fopen("3.txt","w");     for (i=0;i<(int)kn;i++) {         fprintf(f,"%s\n",kk+i*MAXW);     }     fclose(f);     free(kk);     free(ss);     return 0; } //2.txt: //110kV湾沚二回湾223开关谐波监测装置越限报警 //110kV湾沚二回湾223开关谐波监测装置越限报警 //220kV湾铜二回湾223开关谐波监测装置越限报警 //220kV湾铜二回湾223开关谐波监测装置越限报警 //白家冲220kV白格栅二回白07备用 //开封GPS对时装置报警 //铜锣湾2#直流充电柜直流系统故障 //铜锣湾2#直流充电柜直流系统故障 //小北口1#主变低后备保护装置通讯故障 //小北口1#主变低后备保护装置通讯故障 //小北口1#主变低后备保护装置通讯故障 //小北口2#主变差动保护装置通讯故障 //小北口2#主变差动保护装置通讯故障 //小雁溪110kV故障录波装置启动  //3.txt: //铜锣湾 //2# //直流充电柜直流系统故障 //小雁溪 //110kV //故障录波装置启动 //小北口 //1# //主变低后备保护装置通讯故障 //主变差动保护装置通讯故障 //开封 //GPS //对时装置报警 //白家冲 //220kV //白格栅二回白 //07 //备用 //湾铜二回湾 //223 //开关谐波监测装置越限报警 //湾? //b //二回湾

user: user-0
content: 引用 6 楼 mujiok2003 的回复:excel两分钟搞定 关键是不能用，可惜这个了

user: user-0
content: 引用 5 楼 zxhuser-5 的回复:[quote=引用 4 楼 xcg88 的回复:] 求各位大神老师帮帮忙，给点意见也可以。     回zxhuser-5：你给的参考程序不知道咋用。。。先按学校排序，然后按班级排序，最后按成绩排序[/quote]  谢谢你，我回去看看哈！

user: user-4
content: excel两分钟搞定

user: user-5
content: 引用 4 楼 xcg88 的回复:求各位大神老师帮帮忙，给点意见也可以。     回zxhuser-5：你给的参考程序不知道咋用。。。先按学校排序，然后按班级排序，最后按成绩排序

user: user-0
content: 求各位大神老师帮帮忙，给点意见也可以。     回zxhuser-5：你给的参考程序不知道咋用。。。

user: user-0
content: 各位帮帮忙...

user: user-0
content: 谢谢，不是说分三段，应该说是对这个文本进行三次的遍历排序，更加精确的把相同的部分归结为一起。 按第一个关键字排序； 然后对排序后的文本进行第二个关键字排序如下面的  第一个关键字排序后： 小北口1#主变低后备保护装置通讯故障 小北口1#主变低后备保护装置通讯故障 小北口2#主变差动保护装置通讯故障 小北口1#主变低后备保护装置通讯故障 铜锣湾2#直流充电柜直流系统故障 铜锣湾预告警信号 铜锣湾2#直流充电柜直流系统故障 第二个关键字排序后为： 小北口1#主变低后备保护装置通讯故障 小北口1#主变低后备保护装置通讯故障 小北口1#主变低后备保护装置通讯故障 小北口2#主变差动保护装置通讯故障 铜锣湾2#直流充电柜直流系统故障 铜锣湾2#直流充电柜直流系统故障 铜锣湾预告警信号

user: user-5
content: 题目意思是将每条记录分为三段然后排序？ 参考代码：http://pan.baidu.com/s/1ntuNH0X