<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title type="html"><![CDATA[Linux Forum &mdash; Вернуть привычную сортировку имен файлов в Dolphin]]></title>
	<link rel="self" href="https://linuxforum.ru/extern.php?action=feed&amp;tid=32147&amp;type=atom" />
	<updated>2013-11-25T18:31:17Z</updated>
	<generator>PunBB</generator>
	<id>https://linuxforum.ru/viewtopic.php?id=32147</id>
		<entry>
			<title type="html"><![CDATA[Re: Вернуть привычную сортировку имен файлов в Dolphin]]></title>
			<link rel="alternate" href="https://linuxforum.ru/viewtopic.php?pid=378146#p378146" />
			<content type="html"><![CDATA[<p>из интереса немного покопался в исходниках... Итак, собака зарыта между <strong>dolphn</strong>&#039;ом, <strong>kdelibs</strong>, <strong>qtcore</strong> и <strong>icu</strong> (библиотека для работы с юникодом).</p><p>и так, по порядку:<br />1. <strong>dolphin</strong><br />Здесь всё просто:<br /></p><div class="codebox"><pre><code>m_naturalSorting ? KStringHandler::naturalCompare(a, b, Qt::CaseSensitive)
                            : QString::compare(a, b, Qt::CaseSensitive);</code></pre></div><p>т.е. если галочка стоит, то используется умная функция <strong>KStringHandler::naturalCompare()</strong> из <strong>kdelibs</strong>, а если нет, то обычный ламповый <strong>QString::compare()</strong>, который просто сравнивает строки посимвольно... (и, кстати говоря, обладает мелкими недочётами... например, для русского алфавита, ставит ё в конец)</p><p>2. <strong>kdelibs</strong><br /></p><div class="fancy_spoiler_switcher"><div class="fancy_spoiler_switcher_header"><strong>+</strong>&nbsp;kdecore/text/kstringhandler.cpp:302-451</div><div class="fancy_spoiler"><div class="codebox"><pre><code>int KStringHandler::naturalCompare(const QString &amp;_a, const QString &amp;_b, Qt::CaseSensitivity caseSensitivity)
{
    // This method chops the input a and b into pieces of
    // digits and non-digits (a1.05 becomes a | 1 | . | 05)
    // and compares these pieces of a and b to each other
    // (first with first, second with second, ...).
    //
    // This is based on the natural sort order code code by Martin Pool
    // http://sourcefrog.net/projects/natsort/
    // Martin Pool agreed to license this under LGPL or GPL.

    // FIXME: Using toLower() to implement case insensitive comparison is
    // sub-optimal, but is needed because we compare strings with
    // localeAwareCompare(), which does not know about case sensitivity.
    // A task has been filled for this in Qt Task Tracker with ID 205990.
    // http://trolltech.com/developer/task-tracker/index_html?method=entry&amp;id=205990
    QString a;
    QString b;
    if (caseSensitivity == Qt::CaseSensitive) {
        a = _a;
        b = _b;
    } else {
        a = _a.toLower();
        b = _b.toLower();
    }

    const QChar* currA = a.unicode(); // iterator over a
    const QChar* currB = b.unicode(); // iterator over b

    if (currA == currB) {
        return 0;
    }

    while (!currA-&gt;isNull() &amp;&amp; !currB-&gt;isNull()) {
        const QChar* begSeqA = currA; // beginning of a new character sequence of a
        const QChar* begSeqB = currB;
        if (currA-&gt;unicode() == QChar::ObjectReplacementCharacter) {
            return 1;
        }

        if (currB-&gt;unicode() == QChar::ObjectReplacementCharacter) {
            return -1;
        }

        if (currA-&gt;unicode() == QChar::ReplacementCharacter) {
            return 1;
        }

        if (currB-&gt;unicode() == QChar::ReplacementCharacter) {
            return -1;
        }

        // find sequence of characters ending at the first non-character
        while (!currA-&gt;isNull() &amp;&amp; !currA-&gt;isDigit() &amp;&amp; !currA-&gt;isPunct() &amp;&amp; !currA-&gt;isSpace()) {
            ++currA;
        }

        while (!currB-&gt;isNull() &amp;&amp; !currB-&gt;isDigit() &amp;&amp; !currB-&gt;isPunct() &amp;&amp; !currB-&gt;isSpace()) {
            ++currB;
        }

        // compare these sequences
        const QStringRef&amp; subA(a.midRef(begSeqA - a.unicode(), currA - begSeqA));
        const QStringRef&amp; subB(b.midRef(begSeqB - b.unicode(), currB - begSeqB));
        const int cmp = QStringRef::localeAwareCompare(subA, subB);
        if (cmp != 0) {
            return cmp &lt; 0 ? -1 : +1;
        }

        if (currA-&gt;isNull() || currB-&gt;isNull()) {
            break;
        }

        // find sequence of characters ending at the first non-character
        while ((currA-&gt;isPunct() || currA-&gt;isSpace()) &amp;&amp; (currB-&gt;isPunct() || currB-&gt;isSpace())) {
            if (*currA != *currB) {
                return (*currA &lt; *currB) ? -1 : +1;
            }
            ++currA;
            ++currB;
            if (currA-&gt;isNull() || currB-&gt;isNull()) {
                break;
            }
        }

        // now some digits follow...
        if ((*currA == QLatin1Char(&#039;0&#039;)) || (*currB == QLatin1Char(&#039;0&#039;))) {
            // one digit-sequence starts with 0 -&gt; assume we are in a fraction part
            // do left aligned comparison (numbers are considered left aligned)
            while (1) {
                if (!currA-&gt;isDigit() &amp;&amp; !currB-&gt;isDigit()) {
                    break;
                } else if (!currA-&gt;isDigit()) {
                    return +1;
                } else if (!currB-&gt;isDigit()) {
                    return -1;
                } else if (*currA &lt; *currB) {
                    return -1;
                } else if (*currA &gt; *currB) {
                    return + 1;
                }
                ++currA;
                ++currB;
            }
        } else {
            // No digit-sequence starts with 0 -&gt; assume we are looking at some integer
            // do right aligned comparison.
            //
            // The longest run of digits wins. That aside, the greatest
            // value wins, but we can&#039;t know that it will until we&#039;ve scanned
            // both numbers to know that they have the same magnitude.

            bool isFirstRun = true;
            int weight = 0;
            while (1) {
                if (!currA-&gt;isDigit() &amp;&amp; !currB-&gt;isDigit()) {
                    if (weight != 0) {
                        return weight;
                    }
                    break;
                } else if (!currA-&gt;isDigit()) {
                    if (isFirstRun) {
                        return *currA &lt; *currB ? -1 : +1;
                    } else {
                        return -1;
                    }
                } else if (!currB-&gt;isDigit()) {
                    if (isFirstRun) {
                        return *currA &lt; *currB ? -1 : +1;
                    } else {
                        return +1;
                    }
                } else if ((*currA &lt; *currB) &amp;&amp; (weight == 0)) {
                    weight = -1;
                } else if ((*currA &gt; *currB) &amp;&amp; (weight == 0)) {
                    weight = + 1;
                }
                ++currA;
                ++currB;
                isFirstRun = false;
            }
        }
    }

    if (currA-&gt;isNull() &amp;&amp; currB-&gt;isNull()) {
        return 0;
    }

    return currA-&gt;isNull() ? -1 : + 1;
}</code></pre></div></div></div><p><strong>KStringHandler::naturalCompare()</strong> — основное назначение этой замечательной функции это как раз «человеческая» сортировка по-номерам. Но в добавок ко всему она&nbsp; использует в качестве бек-энда для сравнения строк использует QStringRef::localeAwareCompare(); (что в общем правильно).</p><p>3. <strong>QtCore</strong><br />Здесь интерес представляет QString::localeAwareCompare(). Вообще говоря, её реализация зависит от системы, но для unix — это <strong>strcoll()</strong> (стандартная функция libc) и относительно недавно добавленная <strong>icu</strong> (а именно <strong>ucol_strcoll()</strong>). <a href="https://qt.gitorious.org/qt/qt/commit/46163663e956b988719563eae18773a2dedd424e">Соответствующий коммит</a>. Ориентировочно, он должен был войти 4.8-лохматый релиз...</p><p>4. <strong>icu</strong><br />вот эта штука как раз и ставит кириллицу на первое место... ни какими переменными повлиять на её решение мне не удалось... из каких источников она берёт порядок сортировки я тоже не нашёл... но, честно говоря, я не сильно и пытался... копать разные версии я тоже не стал...</p><p>5. Вместо вывода.<br />Проблема эта Обще-Qt-шная. В частности наблюдается и в clementine. Виноват ли в этом icu или нет вопрос ИМХО пока открытый. <br />Средств борьбы я вижу три: <br /></p><ul><li><p>собрать Qt без icu </p></li><li><p>смириться и забыть, </p></li><li><p>околачиваться и промывать мозги людям на багзиллах...</p></li></ul><p>TODO: поискать баги... уже должны быть открыты...</p><br /><br /><p>В качестве бонуса небольшая тестовая программка, которая показывает как разные функции из разных библиотек по-разному сортируют строки...<br /></p><div class="fancy_spoiler_switcher"><div class="fancy_spoiler_switcher_header"><strong>+</strong>&nbsp;strcmper.cpp</div><div class="fancy_spoiler"><div class="codebox"><pre><code>#include &lt;string.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unicode/ucol.h&gt;
#include &lt;QtCore/QString&gt;
#include &lt;QtCore/QLocale&gt;
#include &lt;KStringHandler&gt;

typedef int (*StrCmpFunc)(const char *s1, const char *s2);

static int strcmp_wrapper(const void *p1, const void *p2, void* cmp_func);

void compare_func(const char **strs, size_t strn, const char *label, StrCmpFunc cmp) {
        int i;
        qsort_r(strs, strn, sizeof(char*), strcmp_wrapper, (void *)cmp);
        printf(&quot;%s:&quot;, label);
        for( i=0; i&lt;strn; i++) {
                printf(&quot; %s&quot;,strs[i]);
        }
        putchar(&#039;\n&#039;);
}

static int strcmp_wrapper(const void *p1, const void *p2, void* cmp_func)
{
        StrCmpFunc cmp = (StrCmpFunc) cmp_func;
        return cmp(* (char * const *) p1, * (char * const *) p2);
}

int ucol_strcollUTF8_wrapper(const char *s1, const char *s2) {
        UErrorCode icuStatus = U_ZERO_ERROR;
        UCollator *icuCollator = ucol_open(&quot;ru-RU&quot;, &amp;icuStatus);
        int rv;
        if(!icuCollator) {
                fprintf(stderr, &quot;ucol_open failed: %d(%s)\n&quot;, icuStatus, u_errorName(icuStatus));
                exit(EXIT_FAILURE);
        }

        rv = ucol_strcollUTF8(icuCollator, s1, strlen(s1), s2, strlen(s2), &amp;icuStatus);
        ucol_close(icuCollator);

        return rv;
}

int QString_compare_wrapper(const char *s1, const char *s2) {
        return QString::compare(QString::fromUtf8(s1), QString::fromUtf8(s2));
}

int QString_localeAwareCompare_wrapper(const char *s1, const char *s2) {
        return QString::localeAwareCompare(QString::fromUtf8(s1), QString::fromUtf8(s2));
}

int KStringHandler_naturalCompare_wrapper(const char *s1, const char *s2) {
        return KStringHandler::naturalCompare(QString::fromUtf8(s1), QString::fromUtf8(s2));
}

int main (int argc, char **argv) {
        char cmp_sign;
        if (argc &lt; 3) {
                fprintf(stderr, &quot;Usage: %s &lt;str1&gt; &lt;str2&gt; ...\n&quot;, argv[0]);
                return EXIT_FAILURE;
        }

        compare_func((const char **)argv+1, argc - 1, &quot;strcmp&quot;, strcmp);
        compare_func((const char **)argv+1, argc - 1, &quot;strcoll&quot;, strcoll);
        compare_func((const char **)argv+1, argc - 1, &quot;ucol_strcoll&quot;, ucol_strcollUTF8_wrapper);

        QLocale locale; // we should initialize some qt global objects
        compare_func((const char **)argv+1, argc - 1, &quot;QString::compare&quot;, QString_compare_wrapper);
        compare_func((const char **)argv+1, argc - 1, &quot;QString::localeAwareCompare&quot;, QString_localeAwareCompare_wrapper);
        compare_func((const char **)argv+1, argc - 1, &quot;KStringHandler::naturalCompare&quot;, KStringHandler_naturalCompare_wrapper);
        return 0;
}</code></pre></div></div></div><p><div class="termtitle" style="font-family: sans-serif; position:relative; height:auto; width:auto; background:#3A4061; color:#FFFFFF; padding: 1px;"><b> Консоль:</b></div>
<div class="termcont" style="font-family: Terminus; position:relative; height:auto; width:auto; overflow-x:scroll; white-space: nowrap ; overflow-y:auto;background:#000000; color:#4EF44E; line-height:1.2; padding: 3px; font-size: 1rem; max-height: 60vh"><br /><span style="color: green">alexander@goblin /tmp $</span> g++&nbsp; -I/usr/include/qt4 -I/usr/include/KDE -L/usr/lib64/qt4 -lQtCore -licui18n -lkdecore strcmper.cpp -g <span style="color: cyan"># сборка; пути могут отличаться</span><br /><span style="color: green">alexander@goblin /tmp $</span> ./a.out ё й я q w s 12 2<br />strcmp: 12 2 q s w й я ё<br />strcoll: 12 2 q s w ё й я<br />ucol_strcoll: 12 2 ё й я q s w<br />QString::compare: 12 2 q s w й я ё<br />QString::localeAwareCompare: 12 2 ё й я q s w<br />KStringHandler::naturalCompare: 2 12 ё й я q s w<br /></div></p>]]></content>
			<author>
				<name><![CDATA[Fat-Zer]]></name>
				<uri>https://linuxforum.ru/profile.php?id=11911</uri>
			</author>
			<updated>2013-11-25T18:31:17Z</updated>
			<id>https://linuxforum.ru/viewtopic.php?pid=378146#p378146</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Вернуть привычную сортировку имен файлов в Dolphin]]></title>
			<link rel="alternate" href="https://linuxforum.ru/viewtopic.php?pid=378089#p378089" />
			<content type="html"><![CDATA[<p><strong>verg</strong>, вельми премного благодарен. Однако, все же что сломано в кедах релиза 13.1, ибо в 12.3 при &quot;Правильной сортировке по номерам&quot; все было ОК.</p>]]></content>
			<author>
				<name><![CDATA[urfin]]></name>
				<uri>https://linuxforum.ru/profile.php?id=28931</uri>
			</author>
			<updated>2013-11-25T12:17:41Z</updated>
			<id>https://linuxforum.ru/viewtopic.php?pid=378089#p378089</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Вернуть привычную сортировку имен файлов в Dolphin]]></title>
			<link rel="alternate" href="https://linuxforum.ru/viewtopic.php?pid=378062#p378062" />
			<content type="html"><![CDATA[<p><strong>urfin</strong>, <br /></p><div class="codebox"><pre><code>Настроить Dolphin - Главное - Поведение - снять галку с &quot;Правильная сортировка по номерам&quot;</code></pre></div><br /><br /><p>з.ы. добавил как <a href="http://linuxforum.ru/viewtopic.php?id=31844">совет №18</a></p>]]></content>
			<author>
				<name><![CDATA[verg]]></name>
				<uri>https://linuxforum.ru/profile.php?id=10709</uri>
			</author>
			<updated>2013-11-25T11:26:41Z</updated>
			<id>https://linuxforum.ru/viewtopic.php?pid=378062#p378062</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Вернуть привычную сортировку имен файлов в Dolphin]]></title>
			<link rel="alternate" href="https://linuxforum.ru/viewtopic.php?pid=377714#p377714" />
			<content type="html"><![CDATA[<p><strong>yars</strong>, Нет. И дельфин не причем, это где-то в самом KDE надо копаться. Вот какой компонент в кедах отвечает за сортировку? Знал бы, так в исходниках бы изменил, да пересобрал.</p>]]></content>
			<author>
				<name><![CDATA[urfin]]></name>
				<uri>https://linuxforum.ru/profile.php?id=28931</uri>
			</author>
			<updated>2013-11-24T08:10:24Z</updated>
			<id>https://linuxforum.ru/viewtopic.php?pid=377714#p377714</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Вернуть привычную сортировку имен файлов в Dolphin]]></title>
			<link rel="alternate" href="https://linuxforum.ru/viewtopic.php?pid=377712#p377712" />
			<content type="html"><![CDATA[<p><strong>urfin</strong>, а она по умолчанию уже не установлена в С? Если установлена, то это либо в настройках Дельфина нужно искать, либо патчик какой-нибудь на него откатывать. Даже и не знаю, куда еще думать.</p>]]></content>
			<author>
				<name><![CDATA[yars]]></name>
				<uri>https://linuxforum.ru/profile.php?id=22799</uri>
			</author>
			<updated>2013-11-24T08:06:35Z</updated>
			<id>https://linuxforum.ru/viewtopic.php?pid=377712#p377712</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Вернуть привычную сортировку имен файлов в Dolphin]]></title>
			<link rel="alternate" href="https://linuxforum.ru/viewtopic.php?pid=377707#p377707" />
			<content type="html"><![CDATA[<p><strong>yars</strong>, спасибо, попробую, может получится.</p><p>UPD. Попробовал. Не помогает. Один черт - цифры, русские, английские. Интересно, кто и с какого перепугу порядок сортировки изменил?</p>]]></content>
			<author>
				<name><![CDATA[urfin]]></name>
				<uri>https://linuxforum.ru/profile.php?id=28931</uri>
			</author>
			<updated>2013-11-24T07:28:31Z</updated>
			<id>https://linuxforum.ru/viewtopic.php?pid=377707#p377707</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Вернуть привычную сортировку имен файлов в Dolphin]]></title>
			<link rel="alternate" href="https://linuxforum.ru/viewtopic.php?pid=377706#p377706" />
			<content type="html"><![CDATA[<p>А если LC_COLLATE задать как C? Насколько помню/знаю, порядок сортировки задается этой переменной окружения. Но я с ней не экспериментировал...</p>]]></content>
			<author>
				<name><![CDATA[yars]]></name>
				<uri>https://linuxforum.ru/profile.php?id=22799</uri>
			</author>
			<updated>2013-11-24T07:24:49Z</updated>
			<id>https://linuxforum.ru/viewtopic.php?pid=377706#p377706</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Вернуть привычную сортировку имен файлов в Dolphin]]></title>
			<link rel="alternate" href="https://linuxforum.ru/viewtopic.php?pid=377703#p377703" />
			<content type="html"><![CDATA[<p>Как вернуть привычную сортировку имен файлов в dolphin? В 13.1 сначала идут русские названия файлов, а потом английские. Хотелось бы наоборот.</p>]]></content>
			<author>
				<name><![CDATA[urfin]]></name>
				<uri>https://linuxforum.ru/profile.php?id=28931</uri>
			</author>
			<updated>2013-11-24T07:14:09Z</updated>
			<id>https://linuxforum.ru/viewtopic.php?pid=377703#p377703</id>
		</entry>
</feed>
