#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string.h>
#include <conio.h>
int main()
{
char mass [80][80];
char slovo[80];
int i=0;
int a,k=0;
setlocale(LC_ALL, "Russian");
FILE *f;
f=fopen("text.txt", "r");
if(f==NULL) printf("файл text.txt не открыт\n");
a=i;
printf("Введите слово для поиска: ");
// Здесь должен быть линейный поиск
}
- 53
-
кому не ясна суть вопроса, посмотрите на ответы, если ответы не ясны, оставьте комментарий под соответствующим ответом – jfs Dec 13 '17 at 17:09
3 Answers
Вот ответ, разбирайтесь:
#include "iostream"
#include <string>
#include <fstream>
using namespace std;
int main(){
ifstream file("C://1.txt"); // открыли файл с текстом
string s, find;
char c;
while (!file.eof()){ // прочитали его и заполнили им строку
file.get(c);
s.push_back(c);
}
file.close(); // обязательно закрыли
cout << "enter a world for find: ";
cin >> find;
int pos = s.find(find); // поиск
if (pos == -1)
cout << "not finded" << endl;
else
cout << "finded in " << pos << " simvol position" << endl;
return 0;
}
- 10,021
-
-
1Данный код ищет подстроку, а не слово в файле, т.е., он найдёт "фон" если файл содержит "телефон", хотя самого слова "фон" в файле может и не быть.
Необходимо проверять на ошибки после
file.get(c), в противном случае можно мусор записать вsстроку. Вот рабочий способ считывания файла в строку целиком.Можно ещё упомянуть, что необходимо изменить код, чтобы можно было передать Юникодные имена файлов и входное слово для поиска на Винде.
– jfs Dec 19 '14 at 17:47 -
@jfs счас подумал, можно добавить пару пробелов по обеим концам, чтоб слово полностью совпало, это несложно и загружать можно тоже по словам, ориентируясь по пробелам – perfect Dec 24 '14 at 19:33
-
1@perfect добавить вокруг слова пробелы не достаточно, если слово находится в начале, конце файла или если слова разделены одним из других шести стандартных пробельных символов:
" \t\n\r\f\v"(наиболее вероятно новой строкой'\n'). – jfs Dec 25 '14 at 00:13
istream_iterator<string> + find алгоритм являются простым способом определить, содержит ли файл, данное отделённое пробелами слово, используя линейный поиск:
ifstream file("input.txt");
istream_iterator<string> eof;
bool found = find(istream_iterator<string>(file), eof, word) != eof;
Например, если слово задано с коммандной строки, а файл передаётся на стандартном вводе:
/** $ g++ *.cxx -o find-word && <input.txt ./find-word word
Exit status:
0 -- found word
1 -- not found
2 -- error
*/
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <iterator>
#include <string>
int main(int argc, char* argv[])
{
using namespace std;
if (argc != 2) {
cerr << "Usage: find-word WORD <input.txt\n";
exit(2);
}
string word(argv[1]); // word to search
istream_iterator<string> words(cin), eof;
bool found = find(words, eof, word) != eof;
return found ? 0 : (cin.eof() ? 1 : 2);
}
Поиск работает, потому что istream_iterator<string> вызывает cin >> next_word внутри, который пропускает пробелы по умолчанию (skipws флаг установлен) и find алгоритм затем просто сравнивает next_word == word.
Что такое пробел, а значит и что такое слово может зависеть от текущей локали.
На системах с utf-8 локалью, код работает как есть с произвольным Юникодным текстом (поддержка нескольких языков в одном документе, поддержка эмотиконов и т.д., правда Юникодные пробелы не распознаются). Windows может испортить входной поток за счёт неявных (codepage) преобразований байтового потока -- как прочитать Юникодный текст на Windows лучше задать как отдельный вопрос.
Код читает только одно слово за раз и возвращается как только входное слово обнаружено, то есть код может работать с очень большими файлами и если заданное слово присутствует во вводе, то программа может вернуться раньше -- без считывания всего ввода. Код также информирует об ошибках ввода (cin.eof() тест).
Существует множество строковых алгоритмов, которые помогают найти подстроку в строке, например, алгоритм Ахо—Корасик (мог быть использован для реализации fgrep) может быть эффективнее в некоторых случаях чем наивный линейный поиск. Связанный вопрос: Поиск повторяющихся строк.
- 52,361
-
Ответ ичерпывающий и точный. Давно уж пора создать предмет как философия программирования, в коем вы были бы, не побоюсь этого слова гуру. – АльфаЧ Dec 21 '14 at 11:26
Читайте в цикле файл по словам функцией fscanf() и используйте strcmp() для сравнения.
--
См. man fscanf. Что будет непонятно -- спрашивайте.
Update
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main (int argc, char* argv[])
{
FILE fp;
const char fname;
int rc = 1; // like grep return code
if (!(fp = fopen(fname = (argv[1] ? argv[1]: "1.txt"),"r"))) {
perror(fname);
exit(2);
}
char input[81], word[81];
printf("Enter word: "); fflush(stdout);
if (scanf("%80s", input) == 1) {
printf("search [%s] in %s\n", input, fname);
while(fscanf(fp, "%80s", word) == 1)
if (strcmp(word, input) == 0) {
rc = 0;
printf("Found in pos: %ld\n", ftell(fp));
}
} else
puts("nothing to search");
return rc;
}
Windows 7, emacs e-shell:
c:/Users/avp/src/cc/hashcode $ g++ b.cpp -o b
c:/Users/avp/src/cc/hashcode $ ./b
Enter word: ERRDEMO
search [ERRDEMO] in 1.txt
Found in pos: 591
c:/Users/avp/src/cc/hashcode $
- 46,098
- 6
- 48
- 116
-
Я воспользовался вашим советом. Но в отместку появилась иная проблема, как задать массив, чтобы в него влез весь текст txt в 500 кб. При попытке скомпилировать, ругается. Собственно, вот мой код:
int main()
{
char mass [100][100];<-- как задать массив, чтобы поместился весь текст?
char slovo[80];
int i=0;
int a,k=0;
setlocale(LC_ALL, "Russian");
FILE *f;
f=fopen("text.txt", "r");
if(f==NULL) printf("файл text.txt не открыт\n");while(!feof(f))
{
fscanf(f,"%s",&mass[i]);
printf("%s\n", mass[i]);
i++; }// написал поиск
}
– АльфаЧ Dec 18 '14 at 10:40 -
Используйте лучше тип string для загрузки текста в оперативную память, а потом ищите строку в подстроке http://hashcode.ru/questions/107089/c-%D0%BF%D0%BE%D0%B8%D1%81%D0%BA-%D0%BF%D0%BE%D0%B4%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8-%D0%B2-%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B5 – perfect Dec 18 '14 at 11:45
-
@АльфаЧ, а зачем читать в массив весь текст?
char word[80], slovo[80]; FILE *f = fopen(...); ... while (fscanf(f, "%s", word) == 1) if (strcmp(word, slovo) == 0) { puts("Found"); break; // или чего Вы хотите делать с этом словом }вот и все.
– avp Dec 18 '14 at 13:24 -
Читать в массив текст нужно для того, чтобы произвести линейный поиск. С размерами файла, к примеру, 80 слов, поиск работает, если текст увеличить до 500 Кб, программа отказывается работать. – АльфаЧ Dec 18 '14 at 14:35
-
1@АльфаЧ, думаю, проблема у Вас в чем-то другом.
Кстати, что значит -- отказывается работать?
Опишите подробно все симптомы, сообщения на экране и т.п. (я-то даром ясновиденья обладаю не в полной степени).
--
Попробуйте мой фрагмент с файлом любого размера.
(если опять не работает -- положите код куда-нибудь (например на pastebin.com))
– avp Dec 18 '14 at 14:59 -
Отказывался работать, когда я выводил на экран весь текст, по вашему совету, я убрал выведения массива на экран. Теперь у меня не работает поиск. Я ввожу слово (оно там есть), выводится на экран, "слово не найдено". Мне лишь бы понять вот что, если я увеличу в char mass[100][100]<-- эти значения, выходит ошибка, мол, размер массива превышает допустимый. Ведь если текст у меня состоит из 100 слов, программа работает корректно, размер напрямую зависит от char mass [100][100]. – АльфаЧ Dec 18 '14 at 15:44
-
@АльфаЧ, еще раз прямо говорю, для линейного поиска слова в файле не надо читать его целиком в память.
Читаете файл по одному слову и сравниваете с заданным.
--
Не понимаю, что именно тут непонятно?
– avp Dec 18 '14 at 18:39
(сейчас обновлю ответ примером) -
-
Вместо
argv[1] ?, нужноargc > 1 ?написать, чтобы избежать UB. Нет необходимостиfnameприсваивание внутрьfopen()запихивать.В 2014 году не хорошо жёстко записывать ограничения, такие как
80s. То есть либо нужно динамически под текущее слово память выделять, например, как в моём ответе, либо использовать алгоритм, который умеет сравнивать слово по частям (можно даже по одному байту читатьgetchar()).Следует также упомянуть, что данный код может иметь проблемы с Юникодом на Винде (имя файла, само входное слово).
– jfs Dec 19 '14 at 18:04 -
@jfs, в винде вообще столько проблем, что лучше от нее держаться подальше (хотя данный код в ней (локализованной для cp1251) иногда (ascii или эмулятор терминала, работающий в cp1251) работает).
Что касается систем с UB для
av[1](я, правда, таких не знаю), то IMHO их лучше явно выделять, используя#ifdef.Что же касается %80s, то не стал я грузить автора %m вместе с освобождением динамического буфера или какой-нибудь
– avp Dec 19 '14 at 20:52get_word_file()использующей внутриgetline()и возвращающей указатель и длину (нет смысла как для примера, так и для кучи практических приложений (даже в 2015 году))