
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.216.217] |
![]() |
|
![]() |
|
|
Использую следующий шаблон для создания строки:
"command + *#* + data[1] + *#* + data[n]" Как видно разделителем логических частей служит "*#*" (без кавычек), но может случчится так, что этот набор символов (*#*) может содержаться в data или/и в command. Помогите, пожалуйста, выбрать уникальный разделитель минимальной длины, что бы вероятность его появления в command и data Было минимальным. (я не контролирую содержание этих переменных, оно может быть любым, но его вводит пользователь с клавиатуры). И, соответственно, другой вопрос: Как эту строку порезать и перенести логические части в динамический массив? Я делаю так: ![]() ![]() Information:=Copy(StringFormatedStream.DataString, 1, length(StringFormatedStream.DataString)); i:=0; SetLength(DataArray, 1); DataArray[0]:=UDPServer.Binding.PeerIP; Inc(i); SetLength(DataArray, 2); while Pos('*#*', Information)<>0 do begin DataArray[i]:=Copy(Information, 1, Pos('*#*', Information)-1); Delete(Information, 1, Pos('*#*', Information)+2); Inc(i); SetLength(DataArray, i+1); end; DataArray[i]:=Information; Но, как мне кажется, это громоздко и использует много переменных. Как оптимизировать? Может есть уже готовые функции для разделения строки? |
Сообщ.
#2
,
|
|
|
Выбери разделитель такой, чтобы точно не встречался тексте полей. Например, я бы выбрал #9 - табуляция.
Код разбора строки неоптимальный. Лучше воспользоваться конечным автоматом. |
![]() |
Сообщ.
#3
,
|
|
Цитата Joni Qwest @ Помогите, пожалуйста, выбрать уникальный разделитель минимальной длины, что бы вероятность его появления в command и data Было минимальным Для этого нужно знать что из себя представляют command и data. |
Сообщ.
#4
,
|
|
|
Цитата Как эту строку порезать и перенести логические части в динамический массив? ... Может есть уже готовые функции для разделения строки? У класса TStrings есть пара свойств: Delimiter и DelimitedText. В первое записываешь твой разделитель, во второе - текст с разделителями. В свойстве Items[] получаешь массив подстрок между разделителями. И наоборот, если Items[] уже предварительно заполнено, устанавливаешь нужный Delimiter и в св-ве DelimitedText получаешь нужную результирующую строку. На это Цитата Помогите, пожалуйста, выбрать уникальный разделитель минимальной длины, что бы вероятность его появления в command и data Было минимальным. (я не контролирую содержание этих переменных, оно может быть любым, но его вводит пользователь с клавиатуры). я затрудняюсь что-либо ответить. |
Сообщ.
#5
,
|
|
|
Doesntmatter
Спасибо, попробую. |
Сообщ.
#6
,
|
|
|
![]() ![]() {Строку с указанным разделителем раскладывает в массив строк} procedure SepStrToStrings(const Source: String; const Sep: Char; Strings: TStrings); implementation // const Sep = #9; или #13 procedure SepStrToStrings(const Source: String; const Sep: Char; Strings: TStrings); var I, P, L: Integer; begin P := 1; L := Length(Source); while True do begin while (P <= L) and (Source[P] = Sep) do Inc(P); if P > L then Break; I := P; while (P <= L) and (Source[P] <> Sep) do Inc(P); Strings.Add(Copy(Source, I, P - I)); end; end; |
Сообщ.
#7
,
|
|
|
Спасибо всем, разобрался
|
Сообщ.
#8
,
|
|
|
Цитата Joni Qwest @ Помогите, пожалуйста, выбрать уникальный разделитель минимальной длины, что бы вероятность его появления в command и data Было минимальным. (я не контролирую содержание этих переменных, оно может быть любым, но его вводит пользователь с клавиатуры). Если делать правильно, то не важно встречается разделитель в тексте или нет. Просто надо использовать еще и например кавычки когда в значении поля встретился символ разделителя. Например, посмотри свойство CommaText у tStrings. Добавлено Цитата Joni Qwest @ Как эту строку порезать и перенести логические части в динамический массив? Вот держи вырезку из моего модуля awString (уже публиковавшегося на форуме): интерфейс: ![]() ![]() /////////////////////////////////////// Работа со списками строк (DelimitedText) // Список строк (DelimitedText) это строка, содержащая несколько // элементов разделенных Delimiter. Каждый элемент списка заключается // в QuoteChar (см.AnsiQuotedStr) если он содержит "опасные" // символы: [#0..' ',QuoteChar,Delimiter] // // Например: '"Сысоев Александр Петрович",программист,"ник:""SAP"""' // // Строить список строк можно например так: // s := ''; // for i := 0 to Count-1 do // s := s + DelimitedQ(StringArray[I],QuoteChar,Delimiter) + Delimiter; // // Замечание: функции аналогичны свойствам DelimitedText и CommaText объекта // tStrings. Однако, при интерпретации списка строк есть отличия. // В tStrings (мне кажется из-за ошибки) // строка 'a,' соответствует двум элементам 'a' и '' // а строка 'a, ' соответствует одному элементу 'a' - не странно-ли? // В DelimitedText, обе строки соответствуют двум элементам 'a' и ''. function DelimitedQ (const Str :String; QuoteChar :Char = '"'; Delimiter :Char = ',' ) :String; // Если Str содержит "опасные" символы: [#0..' ',QuoteChar,Delimiter], то // возвращает его заключенным в QuoteChar (см.AnsiQuotedStr). // Иначе, возвращает Str без изменений. function DelimitedText (StringArray :array of string; QuoteChar :Char = '"'; Delimiter :Char = ',' ) :String; overload; // Возвращает список строк построенный из элементов StringArray function DelimitedText (StringList :String; QuoteChar :Char = '"'; Delimiter :Char = ',' ) :tStringDynArray; overload; // Возвращает массив элементов постоенный из списка строк StringList function DelimitedText (StringList :String; Index :Integer; QuoteChar :Char = '"'; Delimiter :Char = ',' ) :String; overload; // Возвращает элемент с номером Index (0..) и списка строк StringList // Если элемент с таким номером отсутствует, возвращает пустую строку. function DelimitedGet (var StringList :String; QuoteChar :Char = '"'; Delimiter :Char = ',' ) :String; overload; // Возвращает первый элемент из списка строк StringList. // Удаляет его, и следующие за ним разделители из StringList. реализация ![]() ![]() /////////////////////////////////////// Работа со списками строк (DelimitedText) // Список строк (DelimitedText) это строка, содержащая несколько // элементов разделенных Delimiter. Каждый элемент списка заключается // в QuoteChar (см.AnsiQuotedStr) если он содержит "опасные" // символы: [#0..' ',QuoteChar,Delimiter] // Например: '"Сысоев Александр Петрович",программист,"ник:""SAP"""' function DelimitedQ (const Str :String; QuoteChar :Char = '"'; Delimiter :Char = ',' ) :String; // Если Str содержит "опасные" символы: [#0..' ',QuoteChar,Delimiter], то // возвращает его заключенным в QuoteChar (см.AnsiQuotedStr). // Иначе, возвращает Str без изменений. var p :PChar; begin Result := Str; if Result <> '' then begin // проверить, если в строке встречается хотя бы один "опасный" символ // то выполнить AnsiQuotedStr p := pChar(Result); while not (p^ in [#0..' ', QuoteChar, Delimiter]) do {$IFDEF MSWINDOWS} p := CharNext(p); {$ELSE} Inc(p); {$ENDIF} if (p^ <> #0) then Result := AnsiQuotedStr(Result, QuoteChar); end; end; // // Обычно, список строк строится так: // s := ''; // for i := 0 to Count-1 do // s := s + DelimitedQ(StringArray[I],QuoteChar,Delimiter) + Delimiter; // // Делать универсаьный DelimitedAdd (см.ниже) нельзя. // Иначе, при // s := ''; DelimitedAdd(s,''); DelimitedAdd(s,''); // в s останется пустая строка, а должно ',' - всетаки есть два пустых элемента. // //procedure DelimitedAdd (var StringList :String; // Element :String; // QuoteChar :Char = '"'; // Delimiter :Char = ',' ); //// Добавляет к списку строк StringList строку Element //begin // if StringList<>'' then StringList := StringList + Delimiter; // StringList := StringList + DelimitedQ(Element,QuoteChar,Delimiter); //end; // function DelimitedText (StringArray :array of string; QuoteChar :Char = '"'; Delimiter :Char = ',' ) :String; // Возвращает список строк построенный из элементов StringArray var i, Count: Integer; begin Count := Length(StringArray); if (Count = 1) and (StringArray[0] = '') then // единственная, пустая строка - требуется спец.обработка поскольку // если этого не сделать, то результатом будет пустая строка, что // соответствует отсутствию строк в списке. Result := QuoteChar + QuoteChar else begin Result := ''; for i := 0 to Count-1 do Result := Result + DelimitedQ(StringArray[I],QuoteChar,Delimiter) + Delimiter; System.Delete(Result, Length(Result), 1); end; end; function DelimitedText (StringList :String; QuoteChar :Char = '"'; Delimiter :Char = ',' ) :tStringDynArray; // Возвращает массив элементов постоенный из списка строк StringList procedure Add(s :String); begin SetLength(Result,Length(Result)+1); Result[Length(Result)-1] := s; end; var p, b: PChar; s: string; begin SetLength(Result,0); if StringList = '' then Exit; p := pChar(StringList); while p^ <> #0 do begin // пропуск "пробелов" перед элементом while p^ in [#1..' '] do p:={$IFDEF MSWINDOWS}CharNext(p){$ELSE}p+1{$ENDIF}; // прочитать элемент if p^ = QuoteChar then // обрамленный элемент s := AnsiExtractQuotedStr(p, QuoteChar) else begin // не обрамленный элемент - ограничивается Delimiter b := P; // или любым символом <= ' ' while (p^ > ' ') and (p^ <> Delimiter) do p:={$IFDEF MSWINDOWS}CharNext(p){$ELSE}p+1{$ENDIF}; SetString(s, b, p-b); end; Add(S); // пропуск "пробелов" после элемента while p^ in [#1..' '] do p:={$IFDEF MSWINDOWS}CharNext(p){$ELSE}p+1{$ENDIF}; // пропуск Delimiter if p^ = Delimiter then begin p:={$IFDEF MSWINDOWS}CharNext(p){$ELSE}p+1{$ENDIF}; if p^ = #0 then Add(''); end; end; end; function DelimitedText (StringList :String; Index :Integer; QuoteChar :Char = '"'; Delimiter :Char = ',' ) :String; // Возвращает элемент с номером Index (0..) и списка строк StringList // Если элемент с таким номером отсутствует, возвращает пустую строку. var a :tStringDynArray; begin a := DelimitedText(StringList,QuoteChar,Delimiter); if Index < Length(a) then Result := a[Index] else Result := ''; end; function DelimitedGet (var StringList :String; QuoteChar :Char = '"'; Delimiter :Char = ',' ) :String; overload; // Возвращает первый элемент из списка строк StringList. // Удаляет его, и следующие за ним разделители из StringList. var p, b: PChar; begin if StringList = '' then begin Result := ''; Exit; end; p := pChar(StringList); // пропуск "пробелов" перед элементом while p^ in [#1..' '] do p:={$IFDEF MSWINDOWS}CharNext(p){$ELSE}p+1{$ENDIF}; // прочитать элемент if p^ = QuoteChar then // обрамленный элемент Result := AnsiExtractQuotedStr(p, QuoteChar) else begin // не обрамленный элемент - ограничивается Delimiter b := P; // или любым символом <= ' ' while (p^ > ' ') and (p^ <> Delimiter) do p:={$IFDEF MSWINDOWS}CharNext(p){$ELSE}p+1{$ENDIF}; SetString(Result, b, p-b); end; // пропуск "пробелов" после элемента while p^ in [#1..' '] do p:={$IFDEF MSWINDOWS}CharNext(p){$ELSE}p+1{$ENDIF}; // пропуск Delimiter if p^ = Delimiter then p:={$IFDEF MSWINDOWS}CharNext(p){$ELSE}p+1{$ENDIF}; Delete(StringList,1,p-pChar(StringList)); end; |