Как найти символ в текстовом файле с

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.txtn";
    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) может быть эффективнее в некоторых случаях чем наивный линейный поиск. Связанный вопрос: Поиск повторяющихся строк.

В этой статье показаны различные методы проверки строки на наличие определенного символа в C#.

1. Использование string.Contains() метод

Строковый класс содержит метод расширения Contains() который перегружен для символов. Возвращает логическое значение true если указанный символ встречается в строке; в противном случае, false. В следующем примере кода показано использование String.Contains() метод для выполнения сравнений с учетом регистра и без учета регистра.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

using System;

public static class StringExtensions

{

    public static bool Contains(this string input, char c)

    {

        return input.Contains(c);

    }

    public static bool ContainsIgnoreCase(this string input, char c)

    {

        return input.ToLower().Contains(c.ToString().ToLower());

    }

}

public class Example

{

    public static void Main()

    {

        string s = «Hello»;

        Console.WriteLine(s.Contains(‘e’));             // True

        Console.WriteLine(s.Contains(‘a’));             // False

        Console.WriteLine(s.ContainsIgnoreCase(‘L’));   // True

    }

}

Скачать  Выполнить код

2. Использование string.IndexOf() метод

Лучшей альтернативой сравнениям без учета регистра является использование string.IndexOf() метод, который может принять StringComparison определение культуры, регистра и правил сортировки для поиска. IndexOf() метод возвращает индекс первого вхождения указанного символа в строку; -1 в противном случае. Это показано ниже:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

using System;

public static class StringExtensions

{

    public static bool Contains(this string s, char c)

    {

        return s.IndexOf(c, StringComparison.CurrentCultureIgnoreCase) != 1;

    }

    public static bool ContainsIgnoreCase(this string s, char c)

    {

        return s.IndexOf(c, StringComparison.InvariantCultureIgnoreCase) != 1;

    }

}

public class Example

{

    public static void Main()

    {

        string s = «Hello»;

        Console.WriteLine(s.Contains(‘e’));             // True

        Console.WriteLine(s.Contains(‘a’));             // False

        Console.WriteLine(s.ContainsIgnoreCase(‘L’));   // True

    }

}

Скачать  Выполнить код

Это все о проверке строки на определенный символ в C#.

Спасибо за чтение.

Пожалуйста, используйте наш онлайн-компилятор размещать код в комментариях, используя C, C++, Java, Python, JavaScript, C#, PHP и многие другие популярные языки программирования.

Как мы? Порекомендуйте нас своим друзьям и помогите нам расти. Удачного кодирования :)

Having a stream for your file, you can build something similar to a typical tokenizer.

In general terms, this works as a finite state machine: you need an enumeration for the states (in this case could be simplified down to a boolean, but I’ll give you the general approach so you can reuse it on similar tasks); and a function implementing the logic. C#’s iterators are quite a fit for this problem, so I’ll be using them on the snippet below. Your function will take the stream as an argument, will use an enumerated value and a char buffer internally, and will yield the strings one by one. You’ll need this near the start of your code file:

using System.Collections.Generic;
using System.IO;
using System.Text;

And then, inside your class, something like this:

enum States {
    OUT,
    IN,
}
IEnumerable<string> GetStrings(TextReader reader) {
    States state=States.OUT;
    StringBuilder buffer;
    int ch;
    while((ch=reader.Read())>=0) {
        switch(state) {
            case States.OUT:
                if(ch=='<') {
                    state=States.IN;
                    buffer=new StringBuilder();
                }
                break;
            case States.IN:
                if(ch=='>') {
                    state=States.OUT;
                    yield return buffer.ToString();
                } else {
                    buffer.Append(Char.ConvertFromUtf32(ch));
                }
                break;
        }
    }
}

The finite-state machine model always has the same layout: while(READ_INPUT) { switch(STATE) {...}}: inside each case of the switch, you may be producing output and/or altering the state. Beyond that, the algorithm is defined in terms of states and state changes: for any given state and input combination, there is an exact new state and output combination (the output can be «nothing» on those states that trigger no output; and the state may be the same old state if no state change is triggered).

Hope this helps.

EDIT: forgot to mention a couple of things:

1) You get a TextReader to pass to the function by creating a StreamReader for a file, or a StringReader if you already have the file on a string.

2) The memory and time costs of this approach are O(n), with n being the length of the file. They seem quite reasonable for this kind of task.

Поиск подстроки

Последнее обновление: 02.03.2023

Функция find() возвращает индекс первого вхождения подстроки или отдельного символа в строке в виде значние я типа size_t:

#include <iostream>
#include <string>

int main()
{
    std::string text {"A friend in need is a friend indeed."};
    std::cout << text.find("ed") << std::endl;      // 14
    std::cout << text.find("friend") << std::endl;  // 2
    std::cout << text.find('d') << std::endl;     // 7
    std::cout << text.find("apple") << std::endl;  // 18446744073709551615
}

Если строка или символ не найдены (как в примере выше в последнем случае), то возвращается специальная константа std::string::npos,
которая представляет очень большое число (как видно из примера, число 18446744073709551615). И при поиске мы можем проверять результат функции find() на равенство этой константе:

if (text.find("banana") == std::string::npos)
{
    std::cout << "Not found" << std::endl;
}

Функция find имеет ряд дополнительных версий. Так, с помощью второго параметра мы можем указать индекс, с которого надо вести поиск:

#include <iostream>
#include <string>

int main()
{
    std::string text {"A friend in need is a friend indeed."};
    // поиск с 10-го индекса
    std::cout << text.find("friend", 10) << std::endl;      // 22
}

Используя эту версию, мы можем написать программу для поиска количества вхождений строки в тексте, то есть выяснить, сколько раз строка встречается в тексте:

#include <iostream>
#include <string>

int main()
{
    std::string text {"A friend in need is a friend indeed."};
    std::string word {"friend"};
    unsigned count{};       // количество вхождений
    for (unsigned i {}; i <= text.length() - word.length(); )
    {
        // получаем индекс
        size_t position = text.find(word, i);
        // если не найдено ни одного вхождения с индекса i, выходим из цикла
        if (position == std::string::npos) break;
        // если же вхождение найдено, увеличиваем счетчик вхождений
        ++count;
        // переходим к следующему индексу после position
        i = position + 1;
    }
    std::cout << "The word is found " << count << " times." << std::endl; // The word is found 2 times.
}

Здесь в цикле пробегаемся по тексту, в котором надо найти строку, пока счетчик i не будет равен text.length() - word.length().
С помощью функции find() получаем индекс первого вхождения слова в тексте, начиная с индекса i. Если таких вхождений не найдено, то выходим из цикла.
Если же найден индекс, то счетчик i получает индекс, следующий за индексом найденного вхождения.

В итоге, поскольку искомое слово «friend» встречается в тексте два раза, то программа выведет

The word is found 2 times.

В качестве альтернативы мы могли бы использовать цикл while:

#include <iostream>
#include <string>

int main()
{
    std::string text {"A friend in need is a friend indeed."};
    std::string word {"friend"};
    unsigned count{};       // количество вхождений
    size_t index{}; // начальный индекс
    while ((index = text.find(word, index)) != std::string::npos)
    {
        ++count;
        index += word.length(); // перемещаем индекс на позицию после завершения слова в тексте
    }
    std::cout << "The word is found " << count << " times." << std::endl;
}

Еще одна версия позволяет искать в тексте не всю строку, а только ее часть. Для этого в качестве третьего параметра передается количество символов из искомой строки, которые программа будет искать в тексте:

#include <iostream>
#include <string>

int main()
{
    std::string text {"A friend in need is a friend indeed."};
    std::string word {"endless"};
    // поиск с 10-го индекса 3 первых символов слова "endless", то есть "end"
    std::cout << text.find("endless", 10, 3) << std::endl;      // 25
}

Стоит отметить, что в этом случае искомая строка должна представлять строковый литерал или строку в С-стиле (например, символьный массив с концевым нулевым байтом).

Функция rfind. Поиск в обратном порядке

Функция rfind() работает аналогично функции find(), принимает те же самые параметры, только ищет подстроку в обратном порядке — с конца строки:

#include <iostream>
#include <string>

int main()
{
    std::string text {"A friend in need is a friend indeed."};
    std::cout << text.rfind("ed") << std::endl;      // 33
    std::cout << text.rfind("friend") << std::endl; // 22
    std::cout << text.rfind('d') << std::endl;     // 34
    std::cout << text.rfind("apple") << std::endl;  // 18446744073709551615
}

Поиск любого из набора символов

Пара функций — find_first_of() и find_last_of() позволяют найти соответственно первый и последний индекс любого из набора символов:

#include <iostream>
#include <string>

int main()
{
    std::string text {"Phone number: +23415678901"};
    std::string letters{"0123456789"};  // искомые символы
    std::cout << text.find_first_of(letters) << std::endl;      // 15
    std::cout << text.find_last_of(letters) << std::endl;      // 25
}

В данном случае ищем в строке «Phone number: +23415678901» первую и последнюю позицию любого из символов из строки «0123456789». То есть таким образом мы найдем начальный и конечный индекс
номера телефона.

Если нам, наоборот, надо найти позиции символов, которые НЕ представляют любой символ из набора, то мы можем использовать функции find_first_not_of() (первая позиция)
и find_last_not_of() (последняя позиция):

#include <iostream>
#include <string>

int main()
{
    std::string text {"Phone number: +23415678901"};
    std::string letters{"0123456789"};  // искомые символы
    std::cout << text.find_first_not_of(letters) << std::endl;      // 0
    std::cout << text.find_last_not_of(letters) << std::endl;      // 14
}

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

#include <iostream>
#include <string>

int main()
{
    std::string text {"When in Rome, do as the Romans do."};    // исходный текст
    const std::string separators{ " ,;:."!?'*n" }; // разделители слов
    unsigned count{};   // счетчик слов
    size_t start { text.find_first_not_of(separators) }; // начальный индекс первого слова
    while (start != std::string::npos) // если нашли слово
    {
        // увеличиваем счетчик слов
        count++;
        size_t end = text.find_first_of(separators, start + 1); // находим, где кончается слово
        if (end == std::string::npos) 
        {
            end = text.length();
        }
        start = text.find_first_not_of(separators, end + 1); // находим начальный индекс следующего слова и переустанавливаем start
    }
    // выводим количество слов
    std::cout << "Text contains " << count << " words" << std::endl;    // Text contains 8 words
}

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

const std::string separators{ " ,;:."!?'*n" }; // разделители слов

Перед обработкой введенного текста фиксируем индекс первого символа первого слова в тексте. Для этого применяется функция find_first_not_of(), которая возвращает
первый индекс любого символа, который не входит в строку separators:

size_t start { text.find_first_not_of(separators) };

Далее в цикле while смотрим, является ли полученный индекс действительным индексом:

while (start != std::string::npos)

Например, если в строке одни только символы из набора separators, тогда функция find_first_not_of() возвратит значение std::string::npos,
что будет означать, что в тексте больше нет непунктационных знаков.

И если start указывает на действительный индекс начала слова, то увеличиваем счетчик слово. Далее находим индекс первого символа из separators, который идет сразу после слова. То есть фактически это индекс после
последнего символа слова, который помещаем в переменную end:

size_t end = text.find_first_of(separators, start + 1); // находим, где закончилось слово

Для нахождения позиции окончания слова используем функцию find_first_of(), которая возвращает первую позицию любого символа из separators, начиная с индекса start+1

Причем может быть, что функция find_first_of() не найдет ни одного символа из separators (например, слово является поседним в тексте, и после него нет никаких знаков пунктуации или пробелов),
в этом случае конечный индекс равен длине текста.

if (end == std::string::npos) // если НЕ найден ни один из символов-разделителей
    end = text.length();        // устанавливаем переменную end на конец текста

После того, как мы нашли начальный индексы слова и его конец, переустанавливаем start на начальный индекс следующего слова и повторяем действия цикла:

start = text.find_first_not_of(separators, end + 1); // находим начальный индекс следующего слова и переустанавливаем start

В конце выводим количество найденных слов.

Мне нужна помощь в поиске в текстовом файле определенного символа, который является началом каждого элемента, который мне нужно прочитать. Притворяться, что это %Мне нужно начать с первого % и продолжить чтение (возможно, в строках), пока я не достигну следующего % и сохранить его в строку.

Я не уверен, как поступить. Нужно ли мне конвертировать все в символы или есть способ поиска, о котором я не знаю?

-2

Решение

Ты можешь использовать std::getline за это. getline будет читать, пока не достигнет разделителя. Вы можете указать свой специальный символ в качестве этого разделителя. Первый звонок getline будет читать все до специального символа, а затем второй вызов будет читать остальные, пока вы не достигнете его снова.

std::ifstream fin("some_text_file.txt");
std::string data;
std::getline(fin, data, '%'); // find start
std::getline(fin, data, '%'); // read data;

Если вам нужно получить строки между двумя специальными символами, вы можете передать полученную строку getline в std::stringstream а затем вы можете прочитать каждую строку в этом потоке.

std:stringstream ss(data)
std::string line;
while (std::getline(ss, line))
{
//do something with line
}

0

Другие решения

использование getline(is, myStr, '#'), где is это поток строк и myStr это выход. Это будет читать в потоке, пока не найдет разделитель #, а затем сохранить все до (но не включая #). Затем вы можете повторить это и просто сохранить все остальные записи, чтобы получить только те, которые находятся между парами # приметы.

0

Понравилась статья? Поделить с друзьями:
  • Как найти номер курьера яндекс еда
  • Как найти свою птицу счастья
  • Как составить программу передач
  • Бендикс стартера как найти
  • Как найти услуги электрика