Как я могу получить TStringList для сортировки по-разному в Delphi

Еще короче: я не знаю, почему вы, ребята, настаиваете на том, чтобы поместить шаблон в класс охраны.

#include 

class scope_guard {
public: 
    template 
    scope_guard(Callable && undo_func) try : f(std::forward(undo_func)) {
    } catch(...) {
        undo_func();
        throw;
    }

    scope_guard(scope_guard && other) : f(std::move(other.f)) {
        other.f = nullptr;
    }

    ~scope_guard() {
        if(f) f(); // must not throw
    }

    void dismiss() noexcept {
        f = nullptr;
    }

    scope_guard(const scope_guard&) = delete;
    void operator = (const scope_guard&) = delete;

private:
    std::function f;
};

Обратите внимание, что код очистки не бросается, иначе вы получаете в том же случае, что и при метании деструкторов.

Использование:

// do step 1
step1();
scope_guard guard1 = [&]() {
    // revert step 1
    revert1();
};

// step 2
step2();
guard1.dismiss();

Мое вдохновение было тем же статьей DrDobbs , что и для OP.


Редактировать 2017/2018: После просмотра (некоторые из) презентации Андрея , с которой связан Андре (я пропустил до конца, где он сказал «Больно близко к идеалу!»). Я понял, что это выполнимо. Большую часть времени вы не хотите иметь дополнительных охранников для всего. Вы просто делаете что-то, и, в конце концов, это либо преуспевает, либо должен произойти откат.

Изменить 2018: добавлена ​​политика выполнения, которая устраняет необходимость вызова dismiss.

#include 
#include 

class scope_guard {
public:
    enum execution { always, no_exception, exception };

    scope_guard(scope_guard &&) = default;
    explicit scope_guard(execution policy = always) : policy(policy) {}

    template
    scope_guard(Callable && func, execution policy = always) : policy(policy) {
        this->operator += (std::forward(func));
    }

    template
    scope_guard& operator += (Callable && func) try {
        handlers.emplace_front(std::forward(func));
        return *this;
    } catch(...) {
        if(policy != no_exception) func();
        throw;
    }

    ~scope_guard() {
        if(policy == always || (std::uncaught_exception() == (policy == exception))) {
            for(auto &f : handlers) try {
                f(); // must not throw
            } catch(...) { /* std::terminate(); ? */ }
        }
    }

    void dismiss() noexcept {
        handlers.clear();
    }

private:
    scope_guard(const scope_guard&) = delete;
    void operator = (const scope_guard&) = delete;

    std::deque> handlers;
    execution policy = always;
};

Использование:

scope_guard scope_exit, scope_fail(scope_guard::execution::exception);

action1();
scope_exit += [](){ cleanup1(); };
scope_fail += [](){ rollback1(); };

action2();
scope_exit += [](){ cleanup2(); };
scope_fail += [](){ rollback2(); };

// ...

13
задан lkessler 2 February 2010 в 03:30
поделиться

3 ответа

Определите "правильно".
i18n сортировка полностью зависит от вашего местонахождения.
Поэтому я полностью согласен с PA, что это не ошибка: поведение по умолчанию Sort работает так, чтобы i18n работал правильно.

Как упоминает Джерри , TStringList.Sort использует AnsiCompareStr и AnsiCompareText (Я объясню в нескольких строках, как это делается).

Но: TStringList гибкий, он содержит Sort, CustomSort и CompareStrings, которые все виртуальные (поэтому их можно переопределить в классе-потомке)
. Кроме того, при вызове CustomSort можно подключить собственную функцию Compare.

В данном ответе находится функция Сравнить, которая делает то, что Вам нужно:

  • Чувствительность к регистру
  • Не используя никакой локали
  • Просто сравните порядковое значение символов строк

CustomSort определено следующим образом:

procedure TStringList.CustomSort(Compare: TStringListSortCompare);
begin
  if not Sorted and (FCount > 1) then
  begin
    Changing;
    QuickSort(0, FCount - 1, Compare);
    Changed;
  end;
end;

По умолчанию метод Sort имеет очень простую реализацию, передавая функцию по умолчанию Compare с вызовом StringListCompareStrings:

procedure TStringList.Sort;
begin
  CustomSort(StringListCompareStrings);
end;

Итак, если вы определите свой собственный TStringListSortCompare совместимый метод Compare, то вы можете определить свой собственный метод сортировки.
TStringListSortCompare определяется как глобальная функция, принимающая TStringList и два индекса, ссылающихся на элементы, которые вы хотите сравнить:

type
  TStringListSortCompare = function(List: TStringList; Index1, Index2: Integer): Integer;

Вы можете использовать StringListCompareStrings в качестве руководства по реализации вашего собственного:

function StringListCompareStrings(List: TStringList; Index1, Index2: Integer): Integer;
begin
  Result := List.CompareStrings(List.FList^[Index1].FString,
                                List.FList^[Index2].FString);
end;

Итак, по умолчанию TStringList. Сортировка откладывается на TList.CompareStrings:

function TStringList.CompareStrings(const S1, S2: string): Integer;
begin
  if CaseSensitive then
    Result := AnsiCompareStr(S1, S2)
  else
    Result := AnsiCompareText(S1, S2);
end;

Который затем использует лежащую внизу функцию Windows API CompareString со стандартной пользовательской локалью LOCALE_USER_DEFAULT:

function AnsiCompareStr(const S1, S2: string): Integer;
begin
  Result := CompareString(LOCALE_USER_DEFAULT, 0, PChar(S1), Length(S1),
    PChar(S2), Length(S2)) - 2;
end;

function AnsiCompareText(const S1, S2: string): Integer;
begin
  Result := CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, PChar(S1),
    Length(S1), PChar(S2), Length(S2)) - 2;
end;

Наконец-то нужная вам функция Compare. Снова ограничения:

  • Case Sensitive
  • Not using any locale
  • Just compare the ordinal value of the characters of the strings

This is the code:

function StringListCompareStringsByOrdinalCharacterValue(List: TStringList; Index1, Index2: Integer): Integer;
var
  First: string;
  Second: string;
begin
  First := List[Index1];
  Second := List[Index2];
  if List.CaseSensitive then
    Result := CompareStr(First, Second)
  else
    Result := CompareText(First, Second);
end;

Delphi isn't closed, quite противоположное: часто это действительно гибкая архитектура.
Часто это просто немного копать, чтобы увидеть, где вы можете подключиться к этой гибкости.

--jeroen

36
ответ дан 1 December 2019 в 18:49
поделиться

AnsiCompareStr / AnsiCompareText учитывает больше, чем количество символов. Они учитывают локаль пользователей, поэтому "e" будет сортироваться вместе с "é", "ê" и т.д.

Для того, чтобы он отсортировался в порядке Ascii, используйте пользовательскую функцию сравнения , как описано здесь

5
ответ дан 1 December 2019 в 18:49
поделиться

AnsiCompareStr (CompareString with LOCALE_USER_DEFAULT) имеет ошибку, так как получает символы с пунктуацией, равной:

e1. é1 e2 é2

правильный порядок (например, для чешского языка):

e1 e2 é1 é2

Кто-нибудь знает, как избежать этой ошибки при заказе?


11.2.2010: Я должен извиниться за то, что описанное поведение полностью соответствует лингвистическим правилам. Хотя я думаю, что это глупо и "плохо", но это не ошибка в функции API.

Проводник в Windows XP использует так называемое интуитивное упорядочивание имен файлов, которое дает лучшие результаты, но не может быть использовано программно.

0
ответ дан 1 December 2019 в 18:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: