На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как прочитать список файлов, поддиректорий в директории?
5. Как запустить программу/файл?
... (продолжение следует) ...

Вопросы, подробно описанные во встроенной справочной системе Delphi, не несут полезной тематической нагрузки, поэтому будут удаляться.
Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.


Внимание
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...
Модераторы: jack128, D[u]fa, Shaggy, Rouse_
  
> Считывание файла с учетом EOL
    Приветствую!

    Имеется файл, в конце строк которого может быть перенос строки как в виде классического для Венды CRLF (#13#10), так и просто CR или LF. Необходимо считать строки этого файла в строковый массив, при этом не теряя эти самые переносы.

    Считываю файл в строковый массив таким образом:
    ExpandedWrap disabled
      Код:
      function TForm1.ImportFromFile(var fileName: string): Boolean;
      var
        StringsFromFile: TStringDynArray;
      begin
        StringsFromFile := TFile.ReadAllLines(fileName);
      ...

    Однако при таком подходе в StringsFromFile[i] попадают строки, но с отрезанными #13#10 / #13 / #10.

    Подскажите, пожалуйста, каким образом можно их учесть при считывании для последующей записи в строковый массив?
    Например, файл содержит следующее:
    Цитата
    Hello#13#10
    World#10
    Again#13
    Тогда в StringsFromFile должно попасть следующее
    StringsFromFile[0] // 'Hello'#$D#$A
    StringsFromFile[1] // 'Hello'#$A
    StringsFromFile[2] // 'Hello'#$D

    Спасибо!

    P.S. Delphi 10.4.
      Ну, как вариант ReadAllText, а затем я не уверен, что SplitString не отрежет делитель, так что писать самому.
      По хорошему же, надо тогда читать файл через OpenText, а потом обрабатывать блоки через ReadBlock. Тут и распараллелить можно.
        Profi,
        Цитата Profi @
        не уверен, что SplitString не отрежет делитель
        Да, он указанный delimiter как раз-таки режет.
        Цитата Profi @
        Тут и распараллелить можно
        А можно чуть подробнее что тут имелось в виду?
          Цитата Profi @
          потом обрабатывать блоки через ReadBlock
          Что-то я не могу сообразить как детектить конец строки... Pos'ом тупо?
          ExpandedWrap disabled
            if (Pos(#13#10, someStr) > 0) or (Pos(#13, someStr) > 0) or (Pos(#10, someStr) > 0)
            Цитата The_Immortal @
            Pos'ом тупо?

            Я бы шёл по строке, как по массиву.
            Нужна ещё переменная copyFrom. Сначала она 1 (я ведь правильно помню, что в 0 лежит длина?).
            Как встретил #10 - сразу копировал бы строку в список и переприсваивал бы copyFrom на i+1.
            С #13 же, надо будет ещё проверить: #10 за ней или нет. От этого сдвиг будет на 1 или на 2.

            Добавлено
            Цитата The_Immortal @
            А можно чуть подробнее что тут имелось в виду?

            Если такой задачи нет, то не обязательно так делать. Но можно тогда запустить несколько потоков, например available/2, и в каждом проверять свой кусок строки. Главное, потом синхронизировать последнюю строку из одного блока с первой из другого, если в первом последняя строка как раз не заканчивается разделителем.
            Сообщение отредактировано: Profi -
              Цитата Profi @
              Нужна ещё переменная copyFrom

              В Delphi есть функция copy(from:string, offset:integer, length:integer):string
              В целом действительно проще написать цикл for
              ExpandedWrap disabled
                var
                  c, i, j, l, n, o: Integer;
                  str: string;
                  arr: array of string;
                begin
                  SetLength(arr, 0);
                  j := 0; // Индекс в массиве arr (количество элементов в массиве arr)
                  l := Length(str); // длина строки, чтобы не пересчитывать её при использовании PChar
                  n := 1; // новый индекс для копирования в массив arr
                  o := 1; // начальный индекс для копирования в массив arr
                  c := 0; // длина строки для копирования в массив arr
                  for i := 1 to l do begin
                    if i < n then continue; // если индекс for меньше начала новой строки, тогда пропускаем итерацию
                    if str[i] = #10 then begin // нашли #10
                      c := i - o; // посчитали длину новой строки
                      n := i + 1; // посчитали индекс начала следующей строки
                      if (l >= i + 1) and (str[i + 1] = #13) then begin // если индекс в пределах строки и нашли #13, тогда объединяем его в #10#13
                        inc(c); // путём увеличения длины строки для копирования
                        inc(n); // и индекса начала новой строки
                      end;
                    end;
                    if str[i]=#13 then begin // нашли #10
                      c := i - o; // посчитали длину новой строки
                      n := i + 1; // посчитали индекс начала следующей строки
                      if (l >= i + 1) and (str[i + 1] = #10) then begin // если индекс в пределах строки и нашли #13, тогда объединяем его в #13#10
                        inc(c); // путём увеличения длины строки для копирования
                        inc(n); // и индекса начала новой строки
                      end;
                    end;
                    if c > 0 then begin // длину строки используем в качестве флага т.к. в ней есть терминаторы, то она не может быть равна 0
                      SetLength(arr, j + 1); // увеличили длину массива arr на 1
                      arr[j] := copy(str, o, c); // добавили в него новую подстроку, скопировав кусок из str
                      inc(j); // увеличили индекс в массиве arr
                      o := n; // установили индекс начала новой строки
                      c := 0; // сбросили флаг
                    end;
                  end;
                end;
              Что-то вроде этого. За очепятки не пинайте

              Добавлено
              Цитата Profi @
              Если такой задачи нет, то не обязательно так делать. Но можно тогда запустить несколько потоков, например available/2, и в каждом проверять свой кусок строки.

              Тогда не просто available/2, а после деления поискать разделители для каждого куска строки.
                Available - в смысле доступных потоков.
                  Цитата Profi @
                  Available - в смысле доступных потоков.

                  Нет. Я имел ввиду, что перед передачей потокам надо бы найти границы строк в разделённых частях. Чтобы после деления потоки не получили строки разбитые деление буфера на несколько частей. Иначе потом понадобится ещё и сцеплять разбитые строки в одну.
                    Цитата macomics @
                    Цитата Profi @
                    Available - в смысле доступных потоков.

                    Нет. Я имел ввиду, что перед передачей потокам надо бы найти границы строк в разделённых частях. Чтобы после деления потоки не получили строки разбитые деление буфера на несколько частей. Иначе потом понадобится ещё и сцеплять разбитые строки в одну.

                    Так я про это и написал:
                    Цитата Profi @
                    Главное, потом синхронизировать последнюю строку из одного блока с первой из другого, если в первом последняя строка как раз не заканчивается разделителем.


                    Добавлено
                    Это будет быстрее, чем сначала подготавливать строку на разбитие, хотя хуже по памяти.
                      Цитата macomics @
                      SetLength(arr, 0);

                      Для чего эта строка?

                      Добавлено
                      Я сделал вот так:
                      В StrIn входящая строка.
                      ExpandedWrap disabled
                        Var
                         I:integer;
                         Buf:String;//Накопление полезных данных
                         StopStr:String;//Накопление стоп данных
                        begin
                          For I:=1 to length(StrIn) do
                            Begin
                              If (StrIn[I]<> #10) and (StrIn[I]<>#13) then
                              Begin
                                If length(StopStr)<>0 then
                                  Begin
                                    memo1.Lines.Add(Buf+StopStr);
                                    Buf:='';
                                    StopStr:='';
                                  End;
                               Buf:=Buf+StrIn[I];
                              End
                              else StopStr:=StopStr+StrIn[I];
                            End;
                         
                          memo1.Lines.Add(Buf+StopStr);
                         
                        end;


                      Вывод просто в memo, замените на что надо
                        Или так, ещё проще:
                        ExpandedWrap disabled
                          Var
                           I:integer;
                           Buf:String;
                           Stop:boolean;//признак стоп символов
                          begin
                          Stop:=false;
                            For I:=1 to length(StrIn) do
                              Begin
                                If (StrIn[I]<> #10) and (StrIn[I]<>#13) then
                                Begin
                                  If Stop then
                                    Begin
                                      memo1.Lines.Add(Buf);
                                      Buf:='';
                                      Stop:=false;
                                    End;
                                End
                                else Stop:=true;
                           
                                Buf:=Buf+StrIn[I];
                              End;
                           
                            memo1.Lines.Add(Buf);
                          Цитата ^D^ima @
                          Или так, ещё проще:

                          И потеряются все пустые строки, а ещё в конце могут быть #13#13

                          Цитата ^D^ima @
                          Для чего эта строка?

                          Просто так. Для комплекта.
                            Цитата macomics @
                            а ещё в конце могут быть #13#13

                            Нет разницы, хоть #10#10


                            Цитата macomics @
                            И потеряются все пустые строки

                            А что такое пустая строка?
                            Какое там стоит закрывающее значение? RLF,CR, LF?
                            Например #13#10#13#10 это сколько пустых строк?

                            Добавлено
                            Если предположить что 2 символа, тогда так:
                            ExpandedWrap disabled
                              Var
                               I:integer;
                               Buf:String;//Накопление полезных данных
                               StopStr:String;//Накопление стоп данных
                              Begin
                              strin:=strin+' ';
                               
                               
                                For I:=1 to length(StrIn) do
                                  Begin
                               
                                    If ((StrIn[I]<> #13) and (StrIn[I]<>#10) and (length(StopStr)<>0)) or
                                    ((Length(StopStr)>=2) or (I=length(StrIn)))
                                     then
                                      Begin
                                          memo1.Lines.Add(Buf+StopStr);
                                          Buf:='';
                                          StopStr:='';
                                      end;
                               
                                    If (StrIn[I]<> #13) and (StrIn[I]<>#10) then Buf:=Buf+StrIn[I]
                                    else StopStr:=StopStr+StrIn[I];
                               
                                  End;
                              End;
                              Цитата ^D^ima @
                              Нет разницы, хоть #10#10

                              В том и суть. Автор пишет, что хочет различать строку только если в конце не пара одинаковых, а два разных разделителя. Или один но уникальный: #13 или #10 или #13#10. И последовательности -#13-#13-" и - это три строки: "-#13", "-#13", "-"
                                Если файл не очень большой, то регулярка типа [^\r\n](\r|\n|\r\n) и там дальше по Matches идти. Возможно, надо будет поиграть с условиями, чтобы при \r\n срабатывала именно эта секция, а не \r
                                Сообщение отредактировано: Fr0sT -
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0999 ]   [ 16 queries used ]   [ Generated: 21.12.24, 12:23 GMT ]