Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Потрепаться";
Текущий архив: 2004.01.16;
Скачать: [xml.tar.bz2];

Вниз

Функция разбивающая строку по разделителям...   Найти похожие ветки 

 
Knight   (2003-12-22 16:16) [0]

... и загоняющая результат в массив. Упростите, кто-нибудь это... желательно без TStrArr...

>> Sha © (22.12.03 15:18) [41]
> Сколько параметров у Explode?
Можно добавить символ разделителя (у меня он передаётся, как первый символ разбиваемой строки). Остальное не важно, лишь бы работало и без дополнительных типов.


type TStrArr=Array of String;

function Explode(Str:String):TStrArr;
var i,k,Len:Integer;
begin
Result:=nil;
Len:=Length(Str);
if Len>0 then begin
k:=1;
for i:=2 to Len+1 do begin
if (i=Len+1) or (Str[i]=Str[1]) then begin
SetLength(Result,Length(Result)+1);
Result[High(Result)]:=Copy(Str,k+1,i-k-1);
k:=i;
end;
end;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var A:TStrArr;
i:Integer;
begin
Memo1.Clear;
A:=Explode(false," Имеется переменная String как ее разбить на символы?");
for i:=0 to Length(A)-1 do Memo1.Lines.Append(A[i]);
A:=nil;
end;


 
Ega23   (2003-12-22 16:18) [1]

Function DelimitedStrToList(sIn:string; Strs:Tstrings;delims:TCharSet):integer;
var i:integer;
s0,s1:string;
ch:char;
begin
if sIn="" then Exit;
strs.Clear;
s0:=sIn;
for i:=0 to 255 do //repl ;; =>; ;
begin
ch:=chr(i);
if ch in Delims then s0:=ReplaceStr(S0,ch+ch, ch+" "+ch);
end;
i:=1;
while true do
begin
s1:=ExtractWord(i,s0,delims);
if s1="" then break;
strs.add(s1);
inc(i);
end;
result:=strs.Count;
end;


Но это с использованием Rx-овского StrUtils


 
Rouse_   (2003-12-22 16:21) [2]

procedure TForm1.Button1Click(Sender: TObject);
var
S: String;
begin
S := "1#2#3#4";
Memo1.Text := StringReplace(S, "#", #13#10, [rfReplaceAll]);
end;


Так пойдет ;)


 
Sha   (2003-12-22 16:26) [3]

// Sha_UnchainFirstWord отделяет первое слово от строки.
// Выделенное слово не содержит разделителей. Оставшаяся после отделения
// часть строки в месте раздела не содержит разделителей.
function Sha_UnchainFirstWord(Delimiter: char; var Tail: string): string;
var
i, len1, len2: integer;
p: pchar;
begin;
UniqueString(Tail);
p:=pointer(Tail);

i:=0; len1:=Length(Tail); len2:=0;
if i<len1 then repeat;
if p[i]<>Delimiter then inc(len2) else if len2>0 then break;
inc(i);
until i>=len1;

if len2>0 then begin;
SetString(Result,pchar(@p[i-len2]),len2);
while (i<len1) and (p[i]=Delimiter) do inc(i);
len1:=len1-i;
if len1=0 then Tail:="" else begin;
System.Move(p[i],p[0],len1+1);
(pinteger(p-4))^:=len1;
end;
end
else begin;
Tail:=""; Result:="";
end;
end;

// Sha_UnchainLastWord отделяет последнее слово от строки.
// Выделенное слово не содержит разделителей. Оставшаяся после отделения
// часть строки в месте раздела не содержит разделителей.
function Sha_UnchainLastWord(Delimiter: char; var Head: string): string;
var
i, len: integer;
p: pchar;
begin;
UniqueString(Head);
p:=pointer(Head);

i:=Length(Head)-1; len:=0;
if i>=0 then repeat;
if p[i]<>Delimiter then inc(len) else if len>0 then break;
dec(i);
until i<0;

if len>0 then begin;
SetString(Result,pchar(@p[i+1]),len);
while (i>=0) and (p[i]=Delimiter) do dec(i);
if i<0 then Head:=""
else begin;
p[i+1]:=#0;
(pinteger(p-4))^:=i+1;
end;
end
else begin;
Head:=""; Result:="";
end;
end;


 
Knight   (2003-12-22 16:37) [4]

>> Ega23 © (22.12.03 16:18) [1]
У меня и то на оди проход, а тут сперва подготовка строки для другой функции, которая использует другую функцию... вобщем через ж..у как-то :)

>> Rouse_ © (22.12.03 16:21) [2]
:)
Вторая часть это демонстрация, что она работает... на самом деле массив используется иначе.

>> Sha © (22.12.03 16:26) [3]
Если я правильно понял, то это что-то другое... :)


 
ИдиотЪ   (2003-12-22 16:40) [5]

так надо в один проход или нормально все-таки сделать ?
пихать все в одну процедуру - будущего не светит


 
Ega23   (2003-12-22 16:41) [6]


> Knight © (22.12.03 16:37) [4]

Тебе чего надо-то? Функция готовая или ты изысками теоретическими занимаешься для совершенствования алгоритма?


 
Sha   (2003-12-22 16:43) [7]

> Knight © (22.12.03 16:37) [4]
> Если я правильно понял, то это что-то другое... :)

А дальше сам :)


 
Sha   (2003-12-22 16:49) [8]

Вот тебе за один проход:
// Sha_WordsToRightMarkedText собирает текст из слов, вставляя между ними
// символ Mark. В конец собранной строки всегда добавляется Mark.
// Специальной обработки кавычек не производится.
// Символы Mark, встреченные в словах, заменяются символами NotMark.
// Если Compress=true, то выполняется сжатие пробелов и управляющих символов в словах.
function Sha_WordsToRightMarkedText(Words: TStrings;
Mark: char= #127; NotMark: char= #32; Compress: boolean= true): string;
var
MarkString: string;
start, stop: pchar;
i: integer;
wd: string;
ch: char;
before, after: boolean;
begin;
MarkString:=Mark;
Result:="";
before:=Compress and (Mark=#32);
after:=Compress and (not before);
with Words do for i:=0 to Count-1 do begin;
wd:=Strings[i];
if before then Sha_SpaceCompressInplace(wd);
start:=pointer(wd);
if start<>nil then begin;
stop:=start + Length(wd);
while true do begin;
ch:=start^;
inc(start);
if (ch>=#32) and (ch<>Mark) then continue;
if start>stop then break;
(start-1)^:=NotMark;
end;
end;
if after then Sha_SpaceCompressInplace(wd);
Result:=Result + wd + MarkString;
end;
end;

// Sha_RightMarkedTextToWords разбивает текст на слова.
// Разделителями слов считаются все управляющие символы (меньшие пробела)
// и Mark. Пробел не является разделителем слов, если только Mark<>#32.
// Специальной обработки кавычек не производится.
// Предварительная очистка списка слов не выполняется.
// Слова длиной меньше MinLength в список слов не включаются.
// Если Compress=true, то выполняется сжатие пробелов и управляющих символов в словах.
procedure Sha_RightMarkedTextToWords(const RightMarkedText: string; Words: TStrings;
Mark: char= #127; MinLength: integer= 0; Compress: boolean= true);
var
start, stop: pchar;
len: integer;
wd: string;
ch: char;
begin;
stop:=pointer(RightMarkedText);
if stop<>nil then repeat;
start:=stop;
repeat;
ch:=stop^;
inc(stop);
until (ch<#32) or (ch=Mark);
len:=stop-start-1;
if (ord(ch) or len<>0) and (len>=MinLength) then begin;
SetString(wd,start,len);
if Compress then Sha_SpaceCompressInplace(wd);
Words.Add(wd);
end;
until ch=#0;
end;


 
Knight   (2003-12-22 16:49) [9]

Сам я в сабже... треба упростить или хотя бы совет, как избавиться от дополнительно типа...


 
Knight   (2003-12-22 16:52) [10]

Странное у вас упрощение... в сабже функция на 17 строк (вместе с объявлением нового типа... :)


 
ИдиотЪ   (2003-12-22 16:54) [11]

вот я помню в турбо-паскале на 286 хт, ну там еще имело смысл чего-то мудрить, но сейчас от ваших измышлений винда быстрее не заработает


 
Sha   (2003-12-22 16:55) [12]

> Knight © (22.12.03 16:49) [9]

Советов больше, чем достаточно :)

Форум больше похож на стартер, чем на мотор.
Тебя толкнули, дальше крутись сам.
Если мотор постоянно глохнет, работа стартера бесполезна.


 
ИдиотЪ   (2003-12-22 16:56) [13]

Sha ©
))
вай, харашо сказал, а


 
Sha   (2003-12-22 16:58) [14]

> Knight © (22.12.03 16:52) [10]
> Странное у вас упрощение... в сабже функция на 17 строк

Так все-таки, сколько параметров у Explode?


 
Rouse_   (2003-12-22 17:12) [15]

> [12] Sha © (22.12.03 16:55)
Мощно задвинул... ;))


 
Knight   (2003-12-22 17:21) [16]

>> Sha © (22.12.03 16:58) [14]
Символ разделителя, можно отдельно, можно как у меня.
Строка, которую надо разбить.

Вывод результата, можно как var процедуры, можно как Result функции.

Пробовал через указатели, но что-то не получается...


 
Sha   (2003-12-22 17:26) [17]

> Knight © (22.12.03 17:21) [16]
а почему вызываешь так:
A:=Explode(false," Имеется переменная String как ее разбить на символы?");


 
Ega23   (2003-12-22 17:26) [18]


> Knight © (22.12.03 17:21) [16]

Ты чего хочешь? Минимальную по коду или полнофункциональную функцию?


 
Sha   (2003-12-22 17:28) [19]

> Ega23 © (22.12.03 17:26) [18]

Тем более, что функция автора ветки, кажется, будет максимальной по времени.


 
Knight   (2003-12-22 19:33) [20]

>> Sha © (22.12.03 17:26) [17]
> а почему вызываешь так:
> A:=Explode(false," Имеется переменная String как ее разбить на символы?");
Sorry... не с той кнопки скопировал... :)
A:=Explode(" Имеется переменная String как ее разбить на символы?");

> Тем более, что функция автора ветки, кажется, будет максимальной по времени.
Почему?


 
Sha   (2003-12-22 19:44) [21]

> Knight © (22.12.03 19:33) [20]
>> Тем более, что функция автора ветки, кажется, будет максимальной по времени.
> Почему?

SetLength(Result,Length(Result)+1); вызывается для каждой буквы каждого слова. А это даже не две функции, как тебе показалось :)

Result[High(Result)]:=Copy(Str,k+1,i-k-1); вызывается для каждой буквы каждого слова. И здесь тоже не две функции, как тебе показалось :)


 
Knight   (2003-12-22 19:52) [22]

> Sha © (22.12.03 19:44) [21]
А если по внимательнее посмотреть... может для каждого слова в предложении?


 
Knight   (2003-12-22 19:54) [23]

В смысле набора символов между двумя разделителями...


 
Sha   (2003-12-22 19:58) [24]

> Knight © (22.12.03 19:52) [22]

Да, точно. Недосмотрел.
Но все равно, если из Sha_RightMarkedTextToWords выбросить лишнее,
то она побыстрее будет.


 
Knight   (2003-12-22 23:24) [25]

>> Sha © (22.12.03 19:58) [24]
Согласен.
С моей цикл на 1.000.000 работает 0:0:6:313.
С твоей (очищенной от лишнего) 0:0:5:422.

А вот следующий вариант выполняется за 0:0:3:547. Хотя если объеденить твой и мой будет ещё меньше, примерно, на секунду :)


function Explode(Str:String):TStrArr;
var i,k,n,LenStr,LenArr:Integer;
Ch:Char;
begin
Result:=nil;
LenStr:=Length(Str);
if LenStr>0 then begin
Ch:=Str[1];
LenArr:=0;
for i:=2 to LenStr do if (Str[i]=Ch) then Inc(LenArr);
SetLength(Result,LenArr+1);
k:=1;
n:=1;
for i:=0 to LenArr do begin
Inc(n);
while (n<=LenStr) and (Str[n]<>Ch) do Inc(n);
Result[i]:=Copy(Str,k+1,n-k-1);
k:=n;
end;
end;
end;


 
Style   (2003-12-22 23:46) [26]

Только чета ваши функции на PHP explode не похожи совсем

function Explode($Separator, $Text) = Array

Причем $Separator - это тоже string;


 
Knight   (2003-12-23 00:08) [27]

>> Style © (22.12.03 23:46) [26]
Ну мне полный аналог и не надо... главное, чтобы строку перегоняло в массив и ладно. :)


 
Fantasist   (2003-12-23 01:41) [28]

procedure GetWords(WordList:TStrings; Text:string; Delimiters:set of char);
var
st,cur:pchar;
tmp:string;
len:Cardinal;
begin
cur:=pointer(text);
while (cur^<>#0) and (cur^ in Delimiters) do inc(cur);
st:=cur;

while cur^<>#0 do
begin
inc(cur);
if cur^ in Delimiters then
begin
len:=Cardinal(cur)-Cardinal(st);
SetLength(tmp,len);
move(st^,pointer(tmp)^,len);
WordList.Add(tmp);

while (cur^<>#0) and (cur^ in Delimiters) do inc(cur);
st:=cur;
end;
end;
end;


 
Style   (2003-12-23 02:03) [29]

Вот написал!

type
TStringArray = Array of string;

function Explode(Separator, Text: string): TStringArray;
var
acount,i, spos: integer;
textaddr,textsize,sepsize: integer;

function getstrlen(address: integer ): integer;
asm
lea eax, pointer(address)
sub eax, $04
mov eax, [eax]
mov result, eax
end;

function getaddr(pstring: pointer ): integer;
asm
lea eax, pointer(pstring)
mov eax, [eax]
mov result, eax
end;

function copyfromaddr(address, pos, count: integer): string;
var
memsize: integer;
mem: pchar;
begin
memsize := count+1;
getmem(mem,memsize);
zeromemory(mem,memsize);
copymemory(mem,pchar(address+pos-1),count);
result := mem;
freemem(mem);
end;

function scanfrompos(pos: integer): boolean;
var j: integer;
begin
result := false;

for j := 1 to sepsize do
begin
if(Text[pos+j] <> separator[j]) then exit;
end;

result := true;
end;

begin
textaddr := GetAddr(@Text);
if(textaddr = 0) then exit;
textsize := GetStrLen(textaddr);
sepsize := GetStrLen(GetAddr(@Separator));

i := $1;
acount := i;
spos := i;

while i < textsize+1 do
begin

if(scanfrompos(i-1)) then
begin
if(spos <> i) then
begin
SetLength(result,acount);
result[acount-1] := copyfromaddr(textaddr,spos,i-spos);

Inc(Acount);
i := i + sepsize;
spos := i;
end;

end
else
Inc(i);
end;

if(spos <= textsize) then
begin
SetLength(result,acount);
result[acount-1] := copyfromaddr(textaddr,spos,textsize-spos+1);
end;

end;


 
Fantasist   (2003-12-23 02:07) [30]


> Knight © (22.12.03 23:24) [25]


Ты не учитываешь, что символы разделители могут идти подряд. Если нужно именно массив, то можно сделать так:


function GetWords(Text:string; Delimiters:set of char):TStrArr;
var
st,cur:pchar;
tmp:string;
len,count:Cardinal;
begin
count:=0;
SetLength(Result,0);

//пропустим разделители
cur:=pointer(text);
while (cur^<>#0) and (cur^ in Delimiters) do inc(cur);
if cur^=#0 then exit;
st:=cur;

//сосчитаем слова
while (cur^<>#0) do
begin
inc(cur);
if (cur^ in Delimiters) do
begin
inc(count);
while (cur^<>#0) and (cur^ in Delimiters) do inc(cur);
end;
end;
SetLength(Result,count+1);
count:=0;

cur:=st;
while cur^<>#0 do
begin
inc(cur);
if cur^ in Delimiters then
begin
len:=Cardinal(cur)-Cardinal(st);
SetLength(Result[count],len);
move(st^,pointer(Result[count])^,len);
inc(count);

while (cur^<>#0) and (cur^ in Delimiters) do inc(cur);
st:=cur;
end;
end;

//последнее слово
len:=Cardinal(cur)-Cardinal(st);
SetLength(Result[count],len);
move(st^,pointer(Result[count])^,len);
end;


 
Style   (2003-12-23 02:11) [31]

Блин скока алгоритмов народ ужо насочинял :)
Дальше чувствую чистый машинный код пойдет или реализацию Explode с помощью MMX технологий хто нить забубенит!

8-)


 
Fantasist   (2003-12-23 02:14) [32]

Единственно что перед параметром Text надо const написать.


 
Fantasist   (2003-12-23 02:20) [33]


> Дальше чувствую чистый машинный код пойдет или реализацию
> Explode с помощью MMX технологий хто нить забубенит!


Это лишнее. Все прекрасно и оптимально реализуется средствами Дельфийского Паскаля. У тебя в коде идея правильная, только не до конца отточеная.


 
Style   (2003-12-23 02:30) [34]

Вот отточил 8)

Кстати можно ускорить

1) сравнивать по слову (32 бита) c разделителем
2) массив создавать в конце вызывая setlength - 1 раз.

function Explode(Separator, Text: string): TStringArray;
var
acount,i, spos: integer;
textaddr,textsize,sepsize: integer;

function getstrlen(address: integer ): integer;
asm
lea eax, pointer(address)
sub eax, $04
mov eax, [eax]
mov result, eax
end;

function getaddr(pstring: pointer ): integer;
asm
lea eax, pointer(pstring)
mov eax, [eax]
mov result, eax
end;

function copyfromaddr(address, pos, count: integer): string;
var
memsize: integer;
mem: pchar;
begin
memsize := count+1;
getmem(mem,memsize);
zeromemory(mem,memsize);
copymemory(mem,pchar(address+pos-1),count);
result := mem;
freemem(mem);
end;

function scanfrompos(pos: integer): boolean;
var j: integer;
begin
result := false;

for j := 1 to sepsize do
begin
if(Text[pos+j] <> separator[j]) then exit;
end;

result := true;
end;

begin

textaddr := GetAddr(@Separator);
if(textaddr = 0) then
begin
SetLength(result,1);
result[0] := text;
exit;
end;
sepsize := GetStrLen(textaddr);

textaddr := GetAddr(@Text);
if(textaddr = 0) then exit;
textsize := GetStrLen(textaddr);

i := $1;
acount := i;
spos := i;

while i < textsize+1 do
begin

if(scanfrompos(i-1)) then
begin
if(spos <> i) then
begin
SetLength(result,acount);
result[acount-1] := copyfromaddr(textaddr,spos,i-spos);

Inc(Acount);
i := i + sepsize;
spos := i;
end else
begin
Inc(Acount);
i := i + sepsize;
spos := i;
end;

end
else
Inc(i)
end;

if(spos <= textsize) then
begin
SetLength(result,acount);
result[acount-1] := copyfromaddr(textaddr,spos,textsize-spos+1);
end;

end;


 
Knight   (2003-12-23 09:21) [35]

>>Fantasist © (23.12.03 02:07) [30]
У меня всё верно. Если разделители повторяются, то считается, что между ними пустая строка ""

>> Style
Ещё не дочитал и не попробовал... коментарий позже... :)


 
Style   (2003-12-23 09:35) [36]

2 Knight :)

Хочу коментариЙ!!!!! Ж8)


 
Style   (2003-12-23 11:28) [37]

Не, ну как функция???

Первый раз чегото с использованием asm попробывал наваять :)


 
Knight   (2003-12-23 12:03) [38]

>> Style © (23.12.03 11:28) [37]
Более 10 секунд... :)


 
Sha   (2003-12-23 12:55) [39]

> Style © (23.12.03 11:28) [37]
> Первый раз чегото с использованием asm попробывал наваять :)

mov result, eax
Это лишнее.

Да и вообще, если писать на Pascal без вызова asm-функций, было бы быстрее :)


 
Knight   (2003-12-23 12:59) [40]

Пока самое быстрое у Fantasist © (23.12.03 02:07) [30]
На 3 сотни миллисекунд быстрее моего.
Хотя лишнего тоже много... :)



Страницы: 1 2 вся ветка

Форум: "Потрепаться";
Текущий архив: 2004.01.16;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.56 MB
Время: 0.011 c
7-49788
MakNik
2003-11-03 09:33
2004.01.16
Помогите, пожалуйста, разобраться с сервисами!


14-49763
VEG
2003-12-22 02:33
2004.01.16
Самый нестандартный алгоритм


3-49464
TATIANA
2003-12-17 15:28
2004.01.16
ДОБАВИТЬ ГРАФИЧЕСКОЕ ИЗОБРАЖЕНИЕ В BLOB-поле


1-49567
Eagle Owl
2004-01-02 15:20
2004.01.16
Code Insight


6-49675
Evgen138
2003-11-12 08:15
2004.01.16
Сообщение в Wundows2000





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский