На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Друзья, соблюдайте, пожалуйста, правила форума и данного раздела:
Данный раздел не предназначен для вопросов и обсуждений, он содержит FAQ-заготовки для разных языков программирования. Любой желающий может разместить здесь свою статью. Вопросы же задавайте в тематических разделах!
• Если ваша статья может быть перенесена в FAQ соответствующего раздела, при условии, что она будет оформлена в соответствии с Требованиями к оформлению статей.
• Чтобы остальным было проще понять, указывайте в описании темы (подзаголовке) название языка в [квадратных скобках]!
Модераторы: Модераторы
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
> Функции Split, Join, GetElement , [Delphi] Строка с разделителями <=> массив элементов
    Функции Split, Join, GetElement

    Апдейт этой темы - т.к. отредактировать тот пост нет возможности, а исходная тема удалена.

    Набор функций для работы со строками, содержащими списки элементов с разделителями. Аналог одноименных функций из JS, PHP. Разделитель может быть любой длины.

    Проверено в Delphi 2009-10, но должно работать и в более старых версиях

    ExpandedWrap disabled
      uses StrUtils; // для PosEx
       
      const
        // Разделитель по умолчанию для Split, Join, GetElement
        DefListDelim = ';';
       
      ...
       
      type
        // Алиас типа вместо нового объявления - в целях совместимости.
        // Можно было бы юзать TArray<string>, но он глючит при использовании в параметрах
        // (i := Low(arr) - пишет Incompatible types)
        TStrArray = Types.TStringDynArray;
       
      ...
       
        function Split(const Str: string; Delim: string = DefListDelim; AllowEmpty: Boolean = True): TStrArray;
        function GetElement(const Str: string; ElemIdx: Integer; Delim: string = DefListDelim): string;
        function Join(const Arr: array of string; Delim: string = DefListDelim; AllowEmpty: Boolean = True): string;
       
      ...
       
      // Расщепление строки Str на массив элементов.
      //   Str - исходная строка
      //   Delim - разделитель элементов в строке (может насчитывать сколько угодно символов)
      //   AllowEmpty - добавлять ли в массив пустые элементы ('elem1;elem2;;elem3').
      //     Потребуется, если исходная строка представляет собой неоднородный список
      //     с фиксированными индексами элементов
      // Пример:
      //   HTMLlines := Split(HTMLPageSource, #13#10, False)
      //   BananaProperties := Split('banana;yellow;;Africa', ';', True)
      function Split(const Str: string; Delim: string; AllowEmpty: Boolean): TStrArray;
      var CurrDelim, NextDelim, CurrIdx: Integer;
      begin
        if Str = '' then begin SetLength(Result, 0); Exit; end;
        CurrDelim := 1; CurrIdx := 0; SetLength(Result, 16);
        repeat
          if CurrIdx = Length(Result) then
            SetLength(Result, CurrIdx + 16);                // проверяем наполненность массива и расширяем при необходимости
          NextDelim := PosEx(Delim, Str, CurrDelim);        // позиция следующего разделителя
          if NextDelim = 0 then NextDelim := Length(Str)+1; // строка кончилась
          Result[CurrIdx] := Copy(Str, CurrDelim, NextDelim - CurrDelim);
          CurrDelim := NextDelim + Length(Delim);
          // если элемент непуст или же пустые допустимы - увеличиваем индекс
          if (Result[CurrIdx] <> '') or AllowEmpty
            then Inc(CurrIdx)
            else Continue;
        until CurrDelim > Length(Str);
        SetLength(Result, CurrIdx);                      // обрезаем массив
      end;
       
      // Получение 0-based элемента из строки с разделителями
      //   Str - исходная строка
      //   ElemIdx - индекс элемента, от 0 до ...
      //   Delim - разделитель элементов в строке (может насчитывать сколько угодно символов)
      // Пример:
      //   value := GetElement('GeneralSettings.SomeIniOption = 123', 1, ' = ');
      function GetElement(const Str: string; ElemIdx: Integer; Delim: string): string;
      var CurrDelim, NextDelim, Idx: Integer;
      begin
        Result := ''; CurrDelim := 1;
        // ElemIdx раз ищем символ разделителя в строке
        for Idx := 1 to ElemIdx do
        begin
          CurrDelim := PosEx(Delim, Str, CurrDelim);
          if CurrDelim = 0 then Exit;
          Inc(CurrDelim, Length(Delim)); // теперь здесь индекс первого символа следующего элемента
        end;
        NextDelim := PosEx(Delim, Str, CurrDelim); // ищем конечный разделитель
        if NextDelim = 0 then NextDelim := Length(Str) + 1;
        Result := Copy(Str, CurrDelim, NextDelim-CurrDelim);
      end;
       
      // Объединение всех строк из массива в одну с разделителями (обратно Split)
      //   Arr - массив строк
      //   Delim - разделитель элементов в строке (может насчитывать сколько угодно символов,
      //     (!) в том числе и ни одного (!) )
      //   AllowEmpty - добавлять ли в строку пустые элементы
      //     Потребуется, если итоговая строка должна представлять собой неоднородный список
      //     с фиксированными индексами элементов
      // Пример:
      //   FruitList := Join(['apples', 'bananas', 'grape'], '; ')
      //   BananaProperties := Join([Banana.Name, Banana.Color, '', Banana.Country], ';', True)
      //   ReJoin := Join(Split('one;two;three'), '|');
      function Join(const Arr: array of string; Delim: string; AllowEmpty: Boolean): string;
      var i: Integer;
      begin
        Result := '';
        for i := Low(Arr) to High(Arr) do
        begin
          if (Arr[i] = '') and not AllowEmpty then Continue;
          if Result = ''
            then Result := Arr[i]
            else Result := Result + Delim + Arr[i];
        end;
      end;


    12.11
    * Тип TStrArray теперь является алиасом Types.TStringDynArray по совету jack128. Более стильный TArray<string>, к сожалению, глючит в качестве параметра.
    * Добавил Join с параметром типа array of string - код полностью аналогичен, но позволяет задавать параметр-массив прямо в коде без использования вспомогательной StrArray

    17.12
    * Убраны StrArray и Join с параметром TStrArray: Join с параметром array of string работает и с переменными типа TStrArray
    Сообщение отредактировано: Fr0sT -
      Fr0sT, а чем не устроила стандартная ExtractStrings? И зачем выходные данные в виде массива? TStrings всяко удобнее, особенно тем, что повсеместно используется в VCL - можно сразу подставлять в него TMemo.Lines или TComboBox.Items и так длаее
        --Ins--, тем, что TStrings надо удалять.
          Цитата Fr0sT @
          --Ins--, тем, что TStrings надо удалять.


          Ну, сомнительный недостаток, имхо. По мне так массивы - крайне неудобная вещь, практически нигде их не использую, заменяя контейнерными классами. Особенно с учетом того, что в интерфейсах VCL именно они и используются, что позволяет их использовать "как есть", а вот массивы почти всегда нужно вручную обрабатывать и преобразовывать к какому-либо виду. Не говоря уже о том, что контейнерные классы по сравнению с массивами поддерживают ряд дополнительных возможностей
            Жалко, что предыдущей темы не осталось - там было в точности то же самое, причем с твоим же участием :)

            Мне лично удобно, очень часто юзаю эти функции для кратковременных задач.
              Цитата Fr0sT @
              Жалко, что предыдущей темы не осталось - там было в точности то же самое, причем с твоим же участием


              Серьезно? :D Я уже и не помню. Ну тогда ладно
                Цитата Fr0sT @
                type
                TStrArray = array of string;

                за такое - растрел на месте полагается.
                Либо TArray<string> должен быть если >=Delphi2009 юзаешь, либо Types.TStringDynArray если раньше.
                Сообщение отредактировано: jack128 -
                  Не стреляйте, дяденька! :)
                  Лучше аргументируй столь категоричное высказывание.
                    Цитата Fr0sT @
                    Лучше аргументируй столь категоричное высказывание.

                    А чего тут аргументировать?? Вот есть три модуля

                    ExpandedWrap disabled
                      unit Unit1;
                       
                      type
                        TStrArray1 = array of string;
                       
                      funciton f1(): TStrArray1;

                    ...

                    ExpandedWrap disabled
                      unit Unit2;
                       
                      type
                        TStrArray2 = array of string;
                       
                      function f2(arr: TStrArray2): TStrArray2;


                    ExpandedWrap disabled
                      unit Unit3;
                       
                      type
                        TStrArray3 = array of string;
                       
                      function f3(arr: TStrArray3): TStrArray3;


                    разработчик каждого нового модуля считает себя самым умными и объявляет новый тип для массива строк.

                    в результате я вместо того, чтобы просто написать f3(f2(f1))

                    вынужден либо unsafe type cast'ом заниматься, либо писать пачку преобразователей TStrArray1 -> TStrArray2 -> TStrArray3.
                      * Тип TStrArray теперь является алиасом Types.TStringDynArray по совету jack128. Более стильный TArray<string>, к сожалению, глючит в качестве параметра.
                      * Добавил Join с параметром типа array of string - код полностью аналогичен, но позволяет задавать параметр-массив прямо в коде без использования вспомогательной StrArray
                        TStringBuilder в D2009 есть?? Если есть, то в Join - он так и просится.
                          jack128, хм, а что, в нём нет такой функции? Интересная идея, погляжу
                            Цитата Fr0sT @
                            * Добавил Join с параметром типа array of string - код полностью аналогичен, но позволяет задавать параметр-массив прямо в коде без использования вспомогательной StrArray

                            В таком случае вариант с параметром Arr:TStrArray является вроде как излишним\масло-масляным, т.к. дин.массив можно передавать вместо открытого массива
                            Сообщение отредактировано: leo -
                              Цитата leo @
                              В таком случае вариант с параметром Arr:TStrArray является вроде как излишним\масло-масляным, т.к. дин.массив можно передавать вместо открытого массива


                              Только вроде как в рантайм преобразование будет, если память не подводит, так что можно второй вариант оставить
                                Цитата --Ins-- @
                                Только вроде как в рантайм преобразование будет

                                Нет, в обоих случаях массив передается непосредственно по указателю, и разница лишь в том, что при Arr:TStringArray ничего доп-но не передается и High(Arr) определяется внутри функции по теневому заголовку Arr (вызовом _DinArrayHigh), а в случае с open array _DinArrayHigh(Arr) вызывается до вызова функции и передается в нее в виде доп.теневого параметра, а внутри функции High(Arr) просто берет это значение из параметра (в данном случае из регистра EDX).
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0386 ]   [ 15 queries used ]   [ Generated: 9.12.24, 13:03 GMT ]