Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2002.12.05;
Скачать: CL | DM;

Вниз

Подсчет слов в файле !!!   Найти похожие ветки 

 
valerchik   (2002-11-21 22:20) [0]

Кто знает как подсчитать сколько каких слов содержиться в файле любого размера ? Как организовать цикл выделения слов из строки текста..........


 
MBo ©   (2002-11-21 22:22) [1]

Сначала определи, что считать словом, как они разделяются, потом по эти разделителям и выбирай слова


 
Anatoly Podgoretsky ©   (2002-11-21 22:28) [2]

Создай список разделителей, остальное дело техники, просто сканирование, С точками только сложность, двоякая у них природа, то часть слова, то разделитель, но можно это отнести к погрешности подсчета.


 
Дмитрий К.К. ©   (2002-11-22 07:30) [3]

Ежели антиресует подсчет количества слов в строке, то вот ссылочка: http://delphibase.endimus.com/?action=viewfunc&topic=strmath&id=10086


 
Separator ©   (2002-11-22 07:49) [4]

Во посмотри, мжет чего и найдешь нужного:

const
StandartDelimiters: TDelimiter = [" ", "!", "@", "(", ")", "-", "|", "\", ";", ":", """, "/", "?", ".", ">", ",", "<"];

function StringToWords(const DelimitedText: string; ResultList: TStrings; Delimiters: TDelimiter = []; ListClear: boolean = true): boolean;
var
i, Len, Prev: word;
TempList: TStringList;

begin
Result:= false;
if (ResultList <> nil) and (DelimitedText <> "") then
try
TempList:= TStringList.Create;
if Delimiters = [] then
Delimiters:= StandartDelimiters;
Len:= 1;
Prev:= 0;
for i:= 1 to Length(DelimitedText) do
begin
if Prev <> 0 then
begin
if DelimitedText[i] in Delimiters then
begin
if Len = 0 then
Prev:= i + 1
else
begin
TempList.Add(copy(DelimitedText, Prev, Len));
Len:= 0;
Prev:= i + 1
end
end
else
Inc(Len)
end
else if not (DelimitedText[i] in Delimiters) then
Prev:= i
end;
if Len > 0 then
TempList.Add(copy(DelimitedText, Prev, Len));
if TempList.Count > 0 then
begin
if ListClear then
ResultList.Assign(TempList)
else
ResultList.AddStrings(TempList);
Result:= true
end;
finally
TempList.Free
end
end;

function StringsToWords(const DelimitedStrings: TStrings; ResultList: TStrings; Delimiters: TDelimiter = []; ListClear: boolean = true): boolean;
begin
if Delimiters = [] then
Delimiters:= StandartDelimiters + [#13, #10]
else
Delimiters:= Delimiters + [#13, #10];
Result:= StringToWords(DelimitedStrings.Text, ResultList, Delimiters, ListClear)
end;


 
Separator ©   (2002-11-22 08:05) [5]

Забыл. Нужно еще добавить вначале:

type
TDelimiter = set of #0..#255;


 
valerchik   (2002-11-22 08:06) [6]

Спасибо мужики.
Ща буду тестить все то что посоветовали :)
Вообще дело все в том...надо чтоб работало как можно быстрее.


 
Song ©   (2002-11-22 08:26) [7]

2Separator © (22.11.02 07:49)
Ты с Паскаля вырос что ли?
CommaText и более ничего не надо :-)


 
MBo ©   (2002-11-22 08:33) [8]

>Song
Все-таки у него не только по запятым и пробелам делит


 
Separator ©   (2002-11-22 08:34) [9]


> CommaText и более ничего не надо :-)

ДА???? Он не всегда правильно резделяет


 
Song ©   (2002-11-22 09:00) [10]

2MBo © (22.11.02 08:33)
Бывает какой-нибудь один разделитель, а два: и запятая и пробел - редко, это уже не БД получается, а какая-то ерунда, составленная очень неряшливо.

2Separator © (22.11.02 08:34)
>>ДА???? Он не всегда правильно резделяет
Ну хорошо не нравится CommaText используй это:

Text:=StringReplace(Text,#32,#13#10,[rfReplaceAll]);

разделит как надо.


 
Separator ©   (2002-11-22 09:21) [11]

А если допустим тест такой: "Это текст!Который надо разбить на слова."
Результат будет такой:
Это
текст!Который
надо
разбить
на
слова.

А результат моей функиции будет такой:
Это
текст
Который
надо
разбить
на
слова


 
Song ©   (2002-11-22 09:27) [12]

const StandartDelimiters: array of Char = [" ", "!", "@", "(", ")", "-", "|", "\", ";", ":", """, "/", "?", ".", ">", ",", "<"];

For t:=0 to High(StandartDelimiters)-1 Do Text:=StringReplace(Text,StandartDelimiters[t],#13#10,[rfReplaceAll]);
ShowMessage("В файле "+IntToStr(объект.Count)+ "слов.")

Я про то, что Ваша громоздкая ф-ия не нужна. Ещё спорить будете?


 
ProgMan ©   (2002-11-22 09:52) [13]

>>Song ©
А теперь сами сравните 2 ответа:
Song © (22.11.02 08:26)
и
Song © (22.11.02 09:27)

Спор ни о чем.
Если у Вас более красивое решение - предложите.
На то Вы и Мастер.
Separator © предложил готовое решение, а Вы начали "пальцевать":
>>Ты с Паскаля вырос что ли? А Вы не пользуетесь Паскалем в Delphi? :-)
Через час "ты" сменилось на "Вы"...
>>Ваша громоздкая ф-ия не нужна

Кстати, а как насчет двух разделителей подряд?


 
Дмитрий К.К. ©   (2002-11-22 09:59) [14]

ProgMan прав.


 
Song ©   (2002-11-22 10:00) [15]

Я его предложил. У меня разделение идёт одной строкой. У меня оно тоже готовое.


 
ProgMan ©   (2002-11-22 10:13) [16]

>>Ты с Паскаля вырос что ли?
>>CommaText и более ничего не надо :-)

Это не готовое решение, а совет по направлению решения.
Чувствуете разницу?

А это уже готовое решение (Ваше):
const StandartDelimiters: array of Char = [" ", "!", "@", "(", ")", "-", "|", "\", ";", ":", """, "/", "?", ".", ">", ",", "<"];

For t:=0 to High(StandartDelimiters)-1 Do Text:=StringReplace(Text,StandartDelimiters[t],#13#10,[rfReplaceAll]);
ShowMessage("В файле "+IntToStr(объект.Count)+ "слов.")


Но Вы его предложили позже, уже в процессе дискуссии, а начали с распальцовки. Вот я о чем...

Так насчет других замечаний?
ты-Вы?
Чем не угодил Паскаль Мастеру Delphi?
два разделителя подряд?


 
Song_   (2002-11-22 10:23) [17]

Сказав "Ты с Паскаля вырос что ли?" я имел ввиду, что человек предоставил решение полностью на конструкциях языка без использования возможностей, которые дают некоторые классы. И уж никак я не хотел кого-либо обидеть. Только Вы увидели в моих словах пренебрежение. Если Вы не знаете как использовать CommaText могу рассказать. Separator"у это не надо, я уверен, что он знает как это делать.
Заметьте я не пальцевал, а указал на более простое и рациональное решение, пальцуете как раз Вы, намекая на какое-то минимое различие между людьми на этом форуме посредством значка.
Насчёт ты-Вы, это проиходит не осознанно, и источники этого, без сомнения, я объяснять не буду.

>>Чем не угодил Паскаль Мастеру Delphi?
С паскалем всё Ok. Что я имел ввиду я написал выше.

>>два разделителя подряд?
Давайте мы поищем ещё кучу условностей. Три разделителя подряд? Пять, десять? Ещё чего-нибудь? Я имею ввиду, что если закрыть эту условность, то можно найти ещё с десяток, а это уже качество ведения б/д. См. Song © (22.11.02 09:00)


 
Separator ©   (2002-11-22 10:30) [18]

Кстати Song, а вы проверяли свое решение? Я вот взял ваш код и ничего не исправляя вставил в дельфи и каков результат? Ничего не работает, точней не совсем работает.
Чтоб избежать последуюзей дискусси вот код:

const
StandartDelimiters: array [1..17] of Char = (" ", "!", "@", "(", ")", "-", "|", "\", ";", ":", """, "/", "?", ".", ">", ",", "<");
var
t: integer;
begin
ListBox2.Items.Clear;
For t:=0 to High(StandartDelimiters)-1 Do
ListBox2.Items.Text:=StringReplace(ListBox1.Items.Strings[ListBox1.ItemIndex],StandartDelimiters[t],#13#10,[rfReplaceAll]);
end;


Результат на строку "Наступит утро, и свои" таков:
Наступит утро
и свои

Результат на строку "В миг лепестки распустит роза..." таков:
В миг лепестки распустит роза...

т.е. без изменений, может я что-то не так делаю?


 
Song_   (2002-11-22 10:42) [19]

Separator ©,
Я не хочу выбирать путь публичного унижения кого бы это ни было на этой конференции, как это сделал ProgMan, поэтому программа (~5 кб) направлена на Ваш почтовый ящик.


 
Separator ©   (2002-11-22 10:47) [20]


> Song_ (22.11.02 10:42)
Просьба если сможешь, то вышли эту программу на vilgelm@mail.kz
А лучше напишите в данном форуме, что я сделал неправильно?


 
Song ©   (2002-11-22 10:53) [21]

Выслал.
>>что я сделал неправильно
Не знаю. У меня всё работает.
Вообще я редко тестирую в самой Дельфи, то что отвечаю в форуме и не из-за того, что "зазнался", а из-за то, что времени не хватает. Но в этот раз я это сделал. Результат перед Вами в письме.


 
unreger   (2002-11-22 11:06) [22]

Что-то подобное такой задаче делается и у меня, но все, что найдется, должно попасть в базу данных для последующей обработки (морфология, синтаксис, поиск границ предложения и проч.)

Правило такое: все что цифробуква = слово, иначе = псевдослово (набор разделителей)
Делает это IsCharAlphaNumeric. Два буфера. TFileStream.
Посимвольное считывание (тут пока не разбирался, но если поток не оптимизирует это дело, то можно будет и свой написать). Как только последовательность цифробукв меняется на последовательность разделителей => в первом буфере собрали слово. Можно считать это еще одним вариантом. И красиво подсвечивать в RichEdit ход анализа.



 
Separator ©   (2002-11-22 11:11) [23]

Вот ваш код:

procedure TForm1.Button1Click(Sender: TObject);
Const StandartDelimiters: array [1..17] of Char = (" ", "!", "@", "(", ")", "-", "|", "\", ";", ":", """, "/", "?", ".", ">", ",", "<");
Var t:Integer;
Str:TStringList;
begin
Str:=TStringList.Create;
With Str Do
try
Text:=Edit1.Text;
For t:=1 to 17 Do Text:=StringReplace(Text,StandartDelimiters[t],#13#10,[rfReplaceAll]);
For t:=Count-1 downto 0 Do IF Trim(Strings[t])="" then Delete(t);
Memo1.Lines.Assign(Str);
ShowMessage("В строке "+IntToStr(Count)+ " слов.");
finally
Free;
end;
end;


Он работет правильно. Вот так и надо было сразу писать. И честно говоря перед тем, как что-либо выложить на форум НАДО проверять на работоспособность, так даже простая описка приведет к хотя бы к тому, что вас будут считать не компетентным.


 
Song ©   (2002-11-22 11:17) [24]

Я предпочитаю, чтобы люди учились программировать, а не брали всё готовое. Поэтому лучше дать человеку научиться, чем сразу ему дать работающий код. Последний он вставит в программу и забудет даже про него, не говоря уж о том, чтобы разобраться чего он делает. Это я Вам говорю по опыту.

>>..так даже простая описка приведет к хотя бы к тому, что вас будут считать не компетентным.
Это вряд ли. Но у Вас может быть своё личное мнение.


 
]?°’???   (2002-11-22 11:18) [25]

>Separator © (22.11.02 10:47)
>А лучше напишите в данном форуме, что я сделал неправильно?


For t:=0 to High(StandartDelimiters)-1 Do
ListBox2.Items.Text:=StringReplace(ListBox1.Items.Strings[ListBox1.ItemIndex],StandartDelimiters[t],#13#10,[rfReplaceAll]);

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

ListBox2.Items.Text:=StringReplace(ListBox1.Items.Text,StandartDelimiters[t],#13#10,[rfReplaceAll]);


 
Separator ©   (2002-11-22 11:32) [26]


> ]?°’??? (22.11.02 11:18)

Просто я хотел, чтоб разбивалась конкретная строка, а не весь текст.


> Song © (22.11.02 11:17)
Не знаю как все, но я прежде чем использовать взятый где-либо код полностью разбираюсь как он работает. Кстати мой метод работает на порядок быстрее :)


 
Anatoly Podgoretsky ©   (2002-11-22 11:33) [27]

Separator © (22.11.02 10:47)
Как минимум это, нарушение границ индексов и также это означает, что у тебя отключена проверка диапазона в компиляторе.

StandartDelimiters: array [ 1..17] of Char =

For t:= 0 to High(StandartDelimiters)-1 Do

Надо

For t := Low(StandartDelimiters) to High(StandartDelimiters) Do

У Song объявлено array of Char, а у тебя array [1..17]
У него тоже мелкая ошибка High(StandartDelimiters)-1 не отработает разделитель "<", а у тебя серьезная.
Мораль: не выключай проверку диапазона или совсем или пока полностью не отладишь программ и не научишься писать безопасный код, в данном случае это использование Low и High

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

P.S. И хотелось бы, что бы дисккуссии велись прилично, без переходов на личности, не добавляйте работы модераторам.


 
]?°’???   (2002-11-22 11:36) [28]

>конкретная строка
ListBox2.Items.Text явно не одна строка


 
Игорь Шевченко ©   (2002-11-22 11:40) [29]

RXLib, однако...


function WordCount(const S: string; const WordDelims: TCharSet): Integer;
var
SLen, I: Cardinal;
begin
Result := 0;
I := 1;
SLen := Length(S);
while I <= SLen do begin
while (I <= SLen) and (S[I] in WordDelims) do Inc(I);
if I <= SLen then Inc(Result);

while (I <= SLen) and not(S[I] in WordDelims) do Inc(I);
end;
end;


 
Separator ©   (2002-11-22 11:41) [30]


> Anatoly Podgoretsky © (22.11.02 11:33)

Полностью согласен, я не доглядел.


 
Игорь Шевченко ©   (2002-11-22 11:42) [31]

Дла файла "любого размера" аналогичная процедура делается через FileMapping и замену String в функции на PChar...


 
Separator ©   (2002-11-22 11:58) [32]


> Игорь Шевченко © (22.11.02 11:40)
Не знаю конкретно в чем дело, но у меня в тексте 2253 слова WordCount выдает 2230, функция Song и моя функция выдают 2253


 
Игорь Шевченко ©   (2002-11-22 12:16) [33]

Separator © (22.11.02 11:58)

Текст и вызов функции в студию ? :-)


 
Separator ©   (2002-11-22 12:33) [34]

type
TCharSet = set of Char;

var
StandartDelimiters: TCharSet = [" ", "!", "@", "(", ")", "-", "|", "\", ";", ":", """, "/", "?", ".", ">", ",", "<"];


function WordCount(const S: string; const WordDelims: TCharSet): Integer;
var
SLen, I: Cardinal;
begin
Result := 0;
I := 1;
SLen := Length(S);
while I <= SLen do begin
while (I <= SLen) and (S[I] in WordDelims) do Inc(I);
if I <= SLen then Inc(Result);

while (I <= SLen) and not(S[I] in WordDelims) do Inc(I);
end;
end;

procedure TForm1.Button4Click(Sender: TObject);
var
i: integer;

begin
i := WordCount(ListBox1.Items.Strings[ListBox1.ItemIndex], spUtils.StandartDelimiters);
ShowMessage(IntToStr(i));
end;

А текст приводит бесполезно, я просто запихал в ListBox несколько текстовых файлов, короче просто набор слов


 
Separator ©   (2002-11-22 12:39) [35]

Ошибка.
i := WordCount(ListBox1.Items.Text, spUtils.StandartDelimiters);


 
Игорь Шевченко ©   (2002-11-22 12:40) [36]

procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessageFmt("Слов: %d", [WordCount(Memo1.Lines.Text, [" ",","])]);
end;

Содержимое мемо:
"А текст приводит бесполезно, я просто запихал в ListBox несколько текстовых файлов, короче просто набор слов".

Результат - 16


 
Separator ©   (2002-11-22 12:50) [37]

Ну так это маленький текст, я подсунул ему тексты нескольких песен Ramstein, если надо могу их привести. Моя функция выдает 1804 слова, а эта функция выдает 1803


 
Song ©   (2002-11-22 12:55) [38]

Separator © (22.11.02 12:50)
Трассировкой пройди :-))


 
valerchik   (2002-11-22 15:01) [39]

Кто знает как подсчитать количество разных слов. Ну что-то вроди этого :

вася 5
купил 23
нашел 2


 
MBo ©   (2002-11-22 15:04) [40]

Заноси их в сортированный StringList, инкрементируя Integer(Objects), если такое слово уже есть


 
Song ©   (2002-11-22 15:09) [41]

2valerchik (22.11.02 15:01)
http://pascal.sources.ru/cgi-bin/forum/YaBB.cgi?board=flame;action=display;num=1036515976;start=1


 
valerchik   (2002-11-22 15:26) [42]

Если делать через массив то долго получается прога работает если файл метров 50


 
Song ©   (2002-11-22 15:39) [43]

Я думаю, это самый быстрый способ. Если делать вложенный цикл и цикл куда будешь заность уже найденные - будет ещё дольше.


 
Alex44   (2002-11-22 16:26) [44]


> Кто знает как подсчитать сколько каких слов содержиться
> в файле любого размера ?


Chto, esli v file 2G? Prosili ne razbit" na slova, a poschitat" kolichestvo! T.e., algorithm dolzhen byt" 1-prohodnyj i bez zagruzki vsego file"a v pamyat"...


 
Игорь Шевченко ©   (2002-11-22 16:34) [45]

Да хоть 4 Гб и за один проход. Какая разница-то ? Считать надо не слова, а последовательности разделителей


 
MegaBass ©   (2002-11-22 16:54) [46]

А не считаете ли вы, что перед тем как учиться писать рограммы, надо выучиться грамматически правильно писать текст ?


 
Yegor Derevenets   (2002-11-22 16:55) [47]

Вообще, вряд ли найдется алгоритм, обрабатывающий файл в 50 мегов достаточно быстро. Вообще - читается файл по строкам и в каждой подсчитывается количество слов. Для подсчета колчества слов в строке можно запустить цикл:

const
Letters=["a".."z", "A".."Z"]; // Добавьте, что не хватает
function WordsAmount (S: string): LongInt;
var
Amount, NChar: LongInt;
LastWasLetter: Boolean;
begin
Amount:=0;
LastWasLetter:=S [1] in Letters;
for NChar:=2 to Length (S)
do begin
if (not (S [NChar] in Letters)) and LastWasLetter
then Inc (Amount);
LastWasLetter:=S [NChar] in Letters;
end;
if LastWasLetter
then Inc (Amount);
WordsAmount:=Amount;
end;

P.S. Я тоже старый (то есть новый) паскалист.
P.P.S. Можно еще написать через файловый поток, почитать Кормена, найти там что нибудь подобное (или Кнута!) и написать...


 
valerchik   (2002-11-22 21:25) [48]

> Заноси их в сортированный StringList, инкрементируя Integer
>(Objects), если такое слово уже есть
Это как ? Хотелось бы посмотреть код программы...


 
MBo ©   (2002-11-23 13:38) [49]

s:string - очередное полученное слово
List:TStringList c Sorted=True

K:=List.IndexOf(s);
if K>=0 then
List.Objects[k]:=Pointer(Integer(List.Objects[k])+1)
else begin
List.Add(s);
List.Objects[List.Count-1]:=Pointer(1);
end;

В таком случае List будет содержать упорядоченный по алфавиту список слов, а Integer(List.Objects[k]) - количество вхождений i-го слова в текст.

Замечу, что при очень большом количестве слов быстрее будет работать метод хэширования.




 
MBo ©   (2002-11-23 13:58) [50]

Пардон, ветка else должна быть такой:
else
List.AddObject(s,Pointer(1));


 
valerchik   (2002-11-23 15:01) [51]

Чёт не работает.
я вот чё делаю:(считываю слова из файла и пытаюсь запихнуть их в массив)

f2:="c:\MyWords.txt";
assignfile(f1,f2);
reset(f1);

while not seekeof(f1) do
begin
readln(f1,s);

k:=List.IndexOf(s);
if k>=0 then
List.Objects[k]:=Pointer(Integer(List.Objects[k])+1)
else
begin
List.AddObject(s,Pointer(1));
end;
end;

closefile(f1);


 
MBo ©   (2002-11-23 15:12) [52]

где у тебя создание объекта списка????

procedure TForm1.Button1Click(Sender: TObject);
var f:textfile;
s:string;
list:tstringlist;
k:integer;
begin
list:=tstringlist.create;
list.sorted:=true;
assignfile(f,"e:\qqq.txt");
reset(f);
while not eof(f) do begin
readln(f,s);
k:=List.IndexOf(s);
if k>=0 then
List.Objects[k]:=Pointer(Integer(List.Objects[k])+1)
else
List.AddObject(s,Pointer(1));
end;
closefile(f);
for k:=0 to list.count-1 do
Memo1.Lines.Add(list[k]+" "+IntToStr(Integer(list.objects[k])));
list.free;
end;


 
valerchik   (2002-11-23 16:43) [53]

спасибо....ща попробую........


 
valerchik   (2002-11-23 17:36) [54]

Вроди все работет :) Спасибо всем :)


 
valerchik   (2002-11-27 10:20) [55]

Пацаны....выручайте...Надо чтоб по-шустрее работало...
Долго он разбивает текст на слова и подсчитывает сколько каких слов было использовани....


 
Mad_Ghost ©   (2002-11-27 10:40) [56]

гы, а че ещё не в курсе что есть такой компонент TRegExpr, или вы с регулярными выражениями не работали?
это же самый рулезный метод обработки текстовых данных, и аналога ему нету.
r: TRegExpr;

r := TRegExpr.Create;
r.Execute := "\S+";
r.Exec(S); //S - текст
for i := 0 to ... до чего до конца, /
r.NextExec; // или че то подобное ... ща точно не помню.
end;
смысл в том чтобы выделять из текста по слову.
выделить слово \S+ , по моему так, хотя сам не пробовал.


 
Smithson ©   (2002-11-27 10:54) [57]

Сформулируй еще раз задачу. Тебе предложили решение, при котором ты получаешь максимум информации из файла. Если тебе надо подсчитать только количество слов (итого), то просто читаешь построчно файл и подсчитаваешь количество разделителей, считая группу разделителей одним. Никакого списка уже не надо и такой код тут уже был.
А если нужна полная статистика, то про скорость можно забыть - аналитика всегда тормоза.


 
valerchik   (2002-11-27 11:26) [58]

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


 
valerchik   (2002-11-27 11:49) [59]

А чё за TRegExpr я про такое не слыхал...
Даже не могу врубиться, как он работает...



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

Текущий архив: 2002.12.05;
Скачать: CL | DM;

Наверх




Память: 0.63 MB
Время: 0.016 c
6-14700
daan_m
2002-10-06 14:26
2002.12.05
Как загрузить прогу на удалённом компе в локальной сети;


4-14876
Dead Stark
2002-10-03 12:03
2002.12.05
Как получить занчения массива VT_UI2, запакованного в Variant?


1-14539
Mad Diger
2002-11-26 18:04
2002.12.05
Помогите решить проблему с MDI приложением


1-14654
Demon[DZ]
2002-11-25 16:00
2002.12.05
Оттенки серого


1-14549
Gerda
2002-11-26 14:06
2002.12.05
TMemo (выделение текста, установка курсора в нужное положение)