【问题标题】:Using native Windows natural order sorting in a custom program在自定义程序中使用原生 Windows 自然顺序排序
【发布时间】:2023-03-11 02:20:01
【问题描述】:

作为一名程序员,您可能不得不使用或创建某种字符串比较函数。通常,这些都很简单:

function compare(s1, s1) { return s1.toLowerCase() - s2.toLowerCase(); }

这适用于绝大多数情况。但是,Windows (XP 和更高版本) 对文件进行不同的排序——而且更好! -- 比一个糟糕的 ASCII 实现。

如何在自定义程序中创建原生 Windows 自然顺序排序的最小、完整和可验证示例?

我读到的所有内容都指向在shlwapi.dll 中使用StrCmpLogicalW 函数。那太棒了!但是如何在自定义 C/C++ 程序中使用这个函数呢?

对重新实现比较功能感兴趣。我已经看过thisthisthisthisthis。这些无疑是非常接近的近似值,但我只想在我的程序中链接或调用 Windows API 函数。

以下是我已经研究并尝试过的其他一些事情:

  • 阅读documentation on shlwapi.dll and StrCmpLogicalW from Microsoft
  • 找到从an earlier Q&A here on StackOverflow 发布的(据称)完整程序
  • 为 C++ 和 C# 版本的 Visual Studio 2010 Express 编译几个小代码示例(fatal error C1190: managed targeted code requires a '/clr' option...真的吗?
  • 为 Visual Studio 2012 Express 编译几个小代码示例,因为一些文章说这将消除早先关于 /clr 选项的编译错误,但只是得到了一堆不同的编译错误
  • 尝试使用 MinGW 为 Eclipse C++ 编译几个小代码示例

当我第一次开始研究这个时,我想,“这只是 Windows API,这很容易!”我还没有想出任何语言的工作程序。

我从事 C/C++ 和 Unix/DOS/Windows shell 脚本编写已有很长时间了,使用 API 从未如此令人厌烦。微软,真丢脸。


另外,我已经阅读了关于 ASCII 排序的咆哮,但谢谢。这些包含一些肥沃的土壤,可以进行一些好的思考。

https://blog.codinghorror.com/sorting-for-humans-natural-sort-order/

http://weblog.masukomi.org/2007/12/10/alphabetical-asciibetical/

【问题讨论】:

    标签: c# c++ sorting winapi dllimport


    【解决方案1】:

    C++:

    #include <windows.h>
    #include <shlwapi.h>
    #pragma comment(lib, "shlwapi.lib")
    
    #include <algorithm>
    #include <vector>
    #include <string>
    #include <iostream>
    
    bool str_cmp_logical(std::wstring const &lhs, std::wstring const &rhs)
    {
        return StrCmpLogicalW(lhs.c_str(), rhs.c_str()) < 1;
    }
    
    int main()
    {
        std::vector<std::wstring> foo{
            L"20string", L"2string", L"3string", L"st20ring", L"st2ring",
            L"st3ring", L"string2", L"string20", L"string3"
        };
    
        for (auto const &f : foo)
            std::wcout << f << L' ';
        std::wcout.put(L'\n');
    
        std::sort(foo.begin(), foo.end(), str_cmp_logical);
    
        for (auto const &f : foo)
            std::wcout << f << L' ';
        std::wcout.put(L'\n');
    }
    

    输出:

    20string 2string 3string st20ring st2ring st3ring string2 string20 string3
    2string 3string 20string st2ring st3ring st20ring string2 string3 string20
    

    尝试使用 MinGW 编译代码失败,因为其包 w32api 附带的 &lt;shlwapi.h&gt; 版本不提供 StrCmpLogicalW() 的原型。当我自己声明时,我得到了

    C:\MinGW\bin>"g++.exe" -lshlwapi C:\Users\sword\source\repos\Codefun\main.cpp
    C:\Users\sword\AppData\Local\Temp\ccMrmLbD.o:main.cpp:(.text+0x23): undefined reference to `StrCmpLogicalW(wchar_t const*, wchar_t const*)'
    collect2.exe: error: ld returned 1 exit status
    

    因此,MinGW 附带的库似乎不知道StrCmpLogicalW()

    不过,它应该适用于 Mingw-w64。

    【讨论】:

    • 这看起来很棒,与我发现的一些早期示例非常匹配。但它直到 VS2010 才编译。 Eclipse 与 MinGW。说“忽略 #pragma 评论 [-Wunknown-pragmas]”
    • "但是直到 VS2010 才编译。"不编译...错误信息是什么?为什么(TF)你在2017年使用VS2010? “带有 MinGW 的 Eclipse 说“忽略 #pragma 注释 [-Wunknown-pragmas]”添加 shlwapi.lib 作为链接器输入您的编译器/链接器可以理解的任何其他方式?
    • 尝试添加这个库是这个问题的一部分。 shlwapi.h 文件很容易找到,但我的系统上不存在shlwapi.lib 文件,我不熟悉如何包含它。我的编程背景主要是 Linux,Windows API 生态系统有点神秘。
    • @JonathanDavidArndt 您需要安装Windows Platform SDK 以获取编写Windows 程序所需的文件(如shlwapi.hshlwapi.lib)。安装时,假设您需要在 C++ 中创建 Windows 桌面应用程序所需的文件。
    • @RaymondChen 至于mingw.org/wiki/MinGW,它附带了自己的一组导入库。
    【解决方案2】:

    事实证明,可以使用 AutoIt 或 AutoHotKey 轻松调用 DLL。

    我将this post from the AutoIt forums 提炼成一个最小的工作示例:

    Func _StrCmpLogicalW($s1, $s2)
       Return DllCall('shlwapi.dll', 'int', 'StrCmpLogicalW', 'wstr', $s1, 'wstr', $s2)[0]
    EndFunc
    

    这是从this archive post on the AutoHotkey forums 提炼出来的一个最小示例:

    _StrCmpLogicalW(s1, s2)
    {
       VarSetCapacity(ws1, StrLen(s1)*2+1,0), DllCall("MultiByteToWideChar", "UInt",0, "UInt",0, "UInt",&s1, "Int",-1, "UInt",&ws1, "Int",StrLen(s1)+1)
       VarSetCapacity(ws2, StrLen(s2)*2+1,0), DllCall("MultiByteToWideChar", "UInt",0, "UInt",0, "UInt",&s2, "Int",-1, "UInt",&ws2, "Int",StrLen(s2)+1)
       return DllCall("Shlwapi.dll\StrCmpLogicalW","UInt",&ws1,"UInt",&ws2)
    }
    

    就是这样!该函数接受两个字符串并返回-1/0/+1,就像世界上其他任何比较函数一样。

    将此与排序算法(例如 _ArrayMultiColSort()_ArrayCustomSort() 用于 AutoIt)结合起来,现在您可以 Quicksort 整个列表。

    (请不要使用Bubble Sort。想想孩子们。)

    【讨论】:

    • 你在制作什么样的机器人:)。
    • 这实际上是受到复制到 USB 播放器上的音乐文件列表的启发,该播放器在文件写入时按顺序读取文件。我天真的 ASCII 比较效果很好! ...只要轨道用前导零编号。有一个很大的文件夹乱序播放,是因为曲目没有编号,所有的文件都被命名为funny。
    • 啊,我总是按最后修改日期排序,所以我按照它们添加到文件系统的顺序来获取它们。
    • Question 没有提到 AutoIt。调用一个winapi函数确实很简单。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-10
    • 2014-05-21
    • 1970-01-01
    • 1970-01-01
    • 2015-05-12
    • 2016-05-24
    • 1970-01-01
    相关资源
    最近更新 更多