标题: [其他] 也谈IF命令的比较顺序 [打印本页]
作者: Demon 时间: 2012-8-15 16:18 标题: 也谈IF命令的比较顺序
众所周知,IF命令的排序规则既不是按照GBK编码的顺序,也不是按照Unicode编码的顺序,而是有着自己的规则,这个规则是什么呢?
在CMD内部,IF命令是调用lstrcmpW函数来比较字符串大小的(《批处理技术内幕:IF命令》),IF命令的比较规则即lstrcmpW函数的比较规则。
lstrcmp(Locale String Compare)函数的排序是与系统的语言与区域设置有关的(参考《Windows 代码页与字符顺序》)。
但是具体怎么排序MSDN却没有说明(至少我没有找到),为了弄清楚默认情况下IF的比较顺序,我写了一个简单C程序:- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <windows.h>
-
- /************************************************************************/
- /* Author: Demon */
- /* Date: 2012/08/15 */
- /* Website: [url]http://demon.tw[/url] */
- /************************************************************************/
-
- #define BUFFER_SIZE 1024
-
- typedef struct _table {
- int cp936;
- wchar_t *unicode;
- char *name;
- } table;
-
- int compare(const void *a, const void *b);
-
- int main()
- {
- table *a;
- int n = 0, i = 0;
- wchar_t *p;
- char buf[BUFFER_SIZE], *p1, *p2;
- FILE *fp1, *fp2;
-
- /* 打开CP936.txt */
- fp1 = fopen("CP936.txt", "rb");
- if (fp1 == NULL) {
- fprintf(stderr, "Can't open CP936.txt\n");
- return 1;
- }
-
- /* 计算映射表数组的大小 */
- while (!feof(fp1) && fgets(buf, BUFFER_SIZE, fp1)) {
- if (strlen(buf) == 0 || buf[0] == '#') continue;
- if (p1 = strchr(buf, '\t')) *p1++ = '\0';
- if (p2 = strchr(p1, '\t')) *p2++ = '\0';
- while (isspace(*p1)) p1++;
- if (!*p1) continue;
- n++;
- }
-
- /* 创建映射表数组 */
- a = (table *) malloc(n * sizeof(table));
-
- /* 重新打开CP936.txt */
- fp1 = freopen("CP936.txt", "rb", fp1);
- if (fp1 == NULL) {
- fprintf(stderr, "Can't reopen CP936.txt\n");
- return 1;
- }
-
- /* 将数据填充到映射表数组 */
- while (!feof(fp1) && fgets(buf, BUFFER_SIZE, fp1)) {
- if (strlen(buf) == 0 || buf[0] == '#') continue;
- if (p1 = strchr(buf, '\t')) *p1++ = '\0';
- if (p2 = strchr(p1, '\t')) *p2++ = '\0';
- while (isspace(*p1)) p1++;
- if (!*p1) continue;
- p = (wchar_t *) malloc(2 * sizeof(wchar_t));
- p[0] = (wchar_t) strtol(p1, NULL, 16);
- p[1] = 0x0000;
- a[i].cp936 = strtol(buf, NULL, 16);
- a[i].unicode = p;
- a[i].name = strdup(p2);
- i++;
- }
-
- /* 快速排序 */
- qsort(a, n, sizeof(table), compare);
-
- /* 打开CP936_SORT.txt */
- fp2 = fopen("CP936_SORT.txt", "wb");
- if (fp2 == NULL) {
- fprintf(stderr, "Can't open CP936_SORT.txt\n");
- return 1;
- }
-
- /* 将排序后的映射表写入文件 */
- for (i = 0; i < n; i++) {
- fprintf(fp2, "0x%02X\t0x%04X\t%s", a[i].cp936, a[i].unicode[0], a[i].name);
- }
-
- /* 释放内存 */
- for (i = 0; i < n; i++) {
- free(a[i].unicode);
- free(a[i].name);
- }
- free(a);
-
- /* 关闭文件并返回 */
- fclose(fp1);
- fclose(fp2);
- return 0;
- }
-
- /* 回调函数 */
- int compare(const void *a, const void *b)
- {
- wchar_t *s1 = ((table *)a)->unicode;
- wchar_t *s2 = ((table *)b)->unicode;
- return lstrcmpW(s1, s2);
- }
复制代码
CP936.TXT可以到Unicode官方网站下载到(http://unicode.org/Public/MAPPIN ... T/WINDOWS/CP936.TXT)。
程序运行后会生成CP936_SORT.txt,里面是排序后的CP936到Unicode的映射表,
第一列是GBK码,第二列是对应的Unicode代码点(Code Point),第三列是字符的Unicode名称。
不想自己编译的话可以下载我编译好的EXE:[attach]5587[/attach]
作者: plp626 时间: 2012-8-20 10:45
很好!宽字符的比较就此搞定。。。
作者: plp626 时间: 2012-8-20 10:48
再有个问题,带引号和不带引号内部怎么处理的?
作者: tiandyoin 时间: 2023-8-12 01:21
本帖最后由 tiandyoin 于 2023-8-12 01:34 编辑
- 默认区域设置(GB2312)排序顺序简列:
- 测试命令:
- if "@VTVT" leq "@FFFF"
- VT 为 0x0B. FF 为 0x0C
- https://ss64.com/nt/sort.html
- '- !"#$%()*,./:;?@[\]^_`~+<=>£01..89aAbBcCdDeE...zZ
- '£¬' 和 ',' 的二进制码几乎相同。'£¬' 是 U+00A3,u+00AC; ',' 是 GB2312 0xA3AC。猜测官网是在搬运文本时转码出错了。
- 自己测得(cp936.nls?,*.nlp):
- [NUL] < [空白字符] < ASCII 剩余前25个控制字符 < (0x7F) < '- < !"#$%&()*,./:;?@[\]^_`{|}~‘’“”<=>+,01..⒆⒇Ⅰ...ⅫaAbBcCdDeE...zZαβ...ЮЯ
- [空白字符]顺序: SPACE,IDEOGRAPHIC SPACE,TAB,LN,,,CR
复制代码
作者: tiandyoin 时间: 2023-8-12 01:35
- C 语言环境排序顺序简列 (不区分大小写):
- 测试命令:
- TYPE "CP936.txt" | SORT /+17 /l "C" /o "CP936_sort.txt"
- https://ss64.com/nt/sort.html
- !"#$%'()*+,-./01..89:;<=>?@[\]^_`aABbcCDdeE...zZ~£¬
- 自己测得(cp936.nls?,*.nlp):
- ASCII 前32个控制字符 < !"#$%&'()*+,-./01..89:;<=>?@[\]^_`AabBCcDdeE...yYZz{|}~ < (0x7F) < àèìòù < Α...Ωαβ...ψωАБ...ЮЯаб...яё < ‘’“” < (0x80) <Ⅰ...Ⅻⅰ...ⅹ < ①...⑩ ⑴...⒇ ⒈...⒛ < ㈠...㈩
- 其中同一字母不区分大小写,前后顺序是随机的,可能是 Aa 也可能是 aA.
- 有意思的是,这一随机不是每次运行脚本都随机,而是每次改变 "CP936.txt" 里的字母序列,
- 会选择多种输出方案中的一种。如果不再改变输入序列,则输出序列固定使用这一种方案。
复制代码
欢迎光临 批处理之家 (http://www.bathome.net/) |
Powered by Discuz! 7.2 |