Как посчитать слова в файле си

Обновлено: 06.07.2024

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

  • 1. Открыть файл, для того, чтобы к нему можно было обращаться. Соответственно, открывать можно для чтения, записи, чтения и записи, переписывания или записи в конец файла и т.п. Когда вы открываете файл, может также произойти куча ошибок – файла может не существовать, это может быть файл не того типа, у вас может не быть прав на работу с файлом и т.д. Всё это необходимо учитывать.
  • 2. Непосредственно работа с файлом - запись и чтение. Здесь также нужно помнить, что мы работаем не с памятью с произвольным доступом, а с буферизированным потоком, что добавляет свою специфику.
  • 3. Закрыть файл. Так как файл является внешним по отношению к программе ресурсом, то если его не закрыть, то он продолжит висеть в памяти, возможно, даже после закрытия программы (например, нельзя будет удалить открытый файл или внести изменения и т.п.). Кроме того, иногда необходимо не закрывать, а "переоткрывать" файл для того, чтобы, например, изменить режим доступа.

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

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

Для работы с файлом необходим объект FILE. Этот объект хранит идентификатор файлового потока и информацию, которая нужна, чтобы им управлять, включая указатель на его буфер, индикатор позиции в файле и индикаторы состояния.

Объект FILE сам по себе является структурой, но к его полям не должно быть доступа. Переносимая программа должна работать с файлом как с абстрактным объектом, позволяющим получить доступ до файлового потока.

Создание и выделение памяти под объект типа FILE осуществляется с помощью функции fopen или tmpfile (есть и другие, но мы остановимся только на этих).

Функция fopen открывает файл. Она получает два аргумента – строку с адресом файла и строку с режимом доступа к файлу. Имя файла может быть как абсолютным, так и относительным. fopen возвращает указатель на объект FILE, с помощью которого далее можно осуществлять доступ к файлу.

Например, откроем файл и запишем в него Hello World

Функция fopen сама выделяет память под объект, очистка проводится функцией fclose. Закрывать файл обязательно, самостоятельно он не закроется.

Функция fopen может открывать файл в текстовом или бинарном режиме. По умолчанию используется текстовый. Режим доступа может быть следующим

Параметры доступа к файлу.
Тип Описание
r Чтение. Файл должен существовать.
w Запись нового файла. Если файл с таким именем уже существует, то его содержимое будет потеряно.
a Запись в конец файла. Операции позиционирования (fseek, fsetpos, frewind) игнорируются. Файл создаётся, если не существовал.
r+ Чтение и обновление. Можно как читать, так и писать. Файл должен существовать.
w+ Запись и обновление. Создаётся новый файл. Если файл с таким именем уже существует, то его содержимое будет потеряно. Можно как писать, так и читать.
a+ Запись в конец и обновление. Операции позиционирования работают только для чтения, для записи игнорируются. Если файл не существовал, то будет создан новый.

Если необходимо открыть файл в бинарном режиме, то в конец строки добавляется буква b, например “rb”, “wb”, “ab”, или, для смешанного режима “ab+”, “wb+”, “ab+”. Вместо b можно добавлять букву t, тогда файл будет открываться в текстовом режиме. Это зависит от реализации. В новом стандарте си (2011) буква x означает, что функция fopen должна завершиться с ошибкой, если файл уже существует. Дополним нашу старую программу: заново откроем файл и считаем, что мы туда записали.

Вместо функции fgets можно было использовать fscanf, но нужно помнить, что она может считать строку только до первого пробела.
fscanf(file, "%127s", buffer);

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

Функции fprintf и fscanf отличаются от printf и scanf только тем, что принимают в качестве первого аргумента указатель на FILE, в который они будут выводить или из которого они будут читать данные. Здесь стоит сразу же добавить, что функции printf и scanf могут быть без проблем заменены функциями fprintf и fscanf. В ОС (мы рассматриваем самые распространённые и адекватные операционные системы) существует три стандартных потока: стандартный поток вывода stdout, стандартный поток ввода stdin и стандартный поток вывода ошибок stderr. Они автоматически открываются во время запуска приложения и связаны с консолью. Пример

Ошибка открытия файла

Если вызов функции fopen прошёл неудачно, то она возвратит NULL. Ошибки во время работы с файлами встречаются достаточно часто, поэтому каждый раз, когда мы окрываем файл, необходимо проверять результат работы

Проблему вызывает случай, когда открывается сразу несколько файлов: если один из них нельзя открыть, то остальные также должны быть закрыты

В простых случаях можно действовать влоб, как в предыдущем куске кода. В более сложных случаях используются методы, подменяющиее RAII из С++: обёртки, или особенности компилятора (cleanup в GCC) и т.п.

Буферизация данных

  • 1) Если он заполнен
  • 2) Если поток закрывается
  • 3) Если мы явно указываем, что необходимо очистить буфер (здесь тоже есть исключения:)).
  • 4) Также очищается, если программа завершилась удачно. Вместе с этим закрываются и все файлы. В случае ошибки выполнения этого может не произойти.

Форсировать выгрузку буфера можно с помощью вызова функции fflush(File *). Рассмотрим два примера – с очисткой и без.

Раскомментируйте вызов fflush. Во время выполнения откройте текстовый файл и посмотрите на поведение.

Буфер файла можно назначить самостоятельно, задав свой размер. Делается это при помощи функции

которая принимает уже открытый FILE и указатель на новый буфер. Размер нового буфера должен быть не меньше чем BUFSIZ (к примеру, на текущей рабочей станции BUFSIZ равен 512 байт). Если передать в качестве буфера NULL, то поток станет небуферизированным. Можно также воспользоваться функцией

  • _IOFBF - полная буферизация. Данные записываются в файл, когда он заполняется. На считывание, буфер считается заполненным, когда запрашивается операция ввода и буфер пуст.
  • _IOLBF - линейная буферизация. Данные записываются в файл когда он заполняется, либо когда встречается символ новой строки. На считывание, буфер заполняется до символа новой строки, когда запрашивается операция ввода и буфер пуст.
  • _IONBF – без буферизации. В этом случае параметры size и buffer игнорируются.

Пример: зададим свой буфер и посмотрим, как осуществляется чтение из файла. Пусть файл короткий (что-нибудь, типа Hello, World!), и считываем мы его посимвольно

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

Функция int feof (FILE * stream); возвращает истину, если конец файла достигнут. Функцию удобно использовать, когда необходимо пройти весь файл от начала до конца. Пусть есть файл с текстовым содержимым text.txt. Считаем посимвольно файл и выведем на экран.

Всё бы ничего, только функция feof работает неправильно. Это связано с тем, что понятие "конец файла" не определено. При использовании feof часто возникает ошибка, когда последние считанные данные выводятся два раза. Это связано с тем, что данные записывается в буфер ввода, последнее считывание происходит с ошибкой и функция возвращает старое считанное значение.

Этот пример сработает с ошибкой (скорее всего) и выведет последний символ файла два раза.

Решение – не использовать feof. Например, хранить общее количество записей или использовать тот факт, что функции fscanf и пр. обычно возвращают число верно считанных и сопоставленных значений.

Примеры

1. В одном файле записаны два числа - размерности массива. Заполним второй файл массивом случайных чисел.

2. Пользователь копирует файл, при этом сначала выбирает режим работы: файл может выводиться как на консоль, так и копироваться в новый файл.

3. Пользователь вводит данные с консоли и они записываются в файл до тех пор, пока не будет нажата клавиша esc. Проверьте программу и посмотрите. как она себя ведёт в случае, если вы вводите backspace: что выводится в файл и что выводится на консоль.

4. В файле записаны целые числа. Найти максимальное из них. Воспользуемся тем, что функция fscanf возвращает число верно прочитанных и сопоставленных объектов. Каждый раз должно возвращаться число 1.

Другое решение считывать числа, пока не дойдём до конца файла.

5. В файле записаны слова: русское слово, табуляция, английское слово, в несколько рядов. Пользователь вводит английское слово, необходимо вывести русское.

Файл с переводом выглядит примерно так

солнце sun
карандаш pen
шариковая ручка pencil
дверь door
окно windows
стул chair
кресло armchair

и сохранён в кодировке cp866 (OEM 866). При этом важно: последняя пара cлов также заканчивается переводом строки.

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

6. Подсчитать количество строк в файле. Будем считывать файл посимвольно, считая количество символов '\n' до тех пор, пока не встретим символ EOF. EOF – это спецсимвол, который указывает на то, что ввод закончен и больше нет данных для чтения. Функция возвращает отрицательное значение в случае ошибки.
ЗАМЕЧАНИЕ: EOF имеет тип int, поэтому нужно использовать int для считывания символов. Кроме того, значение EOF не определено стандартом.

email

Всё ещё не понятно? – пиши вопросы на ящик

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

Подсчет строк:
Ввести счетчик, присвоить ему 0.
Пока не будет достигнут конец файла, считывать очередную строку файла и увеличивать счетчик на 1.

Подсчет символов в строке:
Измерять длину очередной строки с помощью встроенный в язык программирования функции.

Подсчет слов в строке:

  1. Ввести счетчик слов и присвоить ему 0.
  2. Ввести флаговую переменную и присвоить ей 0 (сигнал нахождения вне слова).
  3. Пока не будет достигнут конец строки:
    1. Если очередной символ не пробел и флаг указывает на нахождение вне слова, то увеличить счетчик слов и присвоить флаговой переменной 1 (сигнал нахождения внутри слова).
    2. Если же очередной символ пробел, то присвоить флагу 0.

    Pascal


    Файл выполнен в среде GNU/Linux, компилятор FreePascal. Русские символы считаются за 2 символа. Например, в данном примере во второй строке 9 кириллических символа, пробел и восклицательный знак: 18 + 2 = 20 символов.

    Язык Си

    посчитать количество строк в файле си


    Тот же "эффект", что и в Паскале: кириллический символ считается за 2.

    Функция fgets() считывает строку вместе с символом перехода на новую строку. Аргумент N не позволяет считать больше указанного количества символов, но длина строки определяется по количеству считанных (т.е. фактической длиной строки).

    Python

    python количество строк в файле


    Символ перехода на новую строку учитывается.

    КуМир

    Здесь считается общее количество слов и символов.

    Basic-256


    Переход на новую строку учитывается как символ.


    var
    f: text;
    s: string;
    line, chr, wrd: word;
    i: byte;
    flag: boolean;
    begin
    assign(f,'text.txt');
    reset(f);
    line := 0;
    while not EOF(f) do begin
    readln(f,s);
    write(s, ' - ');

    chr := length(s);
    write(chr, ' симв., ');

    wrd := 0;
    flag := false;
    for i:=1 to chr do
    if (s[i] ' ') and (flag = false) then begin
    wrd := wrd + 1;
    flag := true;
    end
    else
    if s[i] = ' ' then flag := false;
    writeln(wrd, ' сл.');
    end;
    close(f);
    writeln(line,' стр.');
    end.

    Hello world! - 12 симв., 2 сл.
    Привет мир! - 20 симв., 2 сл.
    One, two, three - 15 симв., 3 сл.
    Один, два, три - 24 симв., 3 сл.
    4 стр.


    Файл выполнен в среде GNU/Linux, компилятор FreePascal. Русские символы считаются за 2 символа. Например, в данном примере во второй строке 9 кириллических символа, пробел и восклицательный знак: 18 + 2 = 20 символов.

    посчитать количество строк в файле си

    word = 0;
    flag = 0;
    for (i=0; i

    python количество строк в файле

    f = open('text.txt')
    line = 0
    for i in f:
    line += 1

    flag = 0
    word = 0
    for j in i:
    if j != ' ' and flag == 0:
    word += 1
    flag = 1
    elif j == ' ':
    flag = 0

    Hello world!
    13 симв. 2 сл.
    Привет мир!
    12 симв. 2 сл.
    One, two, three
    16 симв. 3 сл.
    Один, два, три
    15 симв. 3 сл.
    4 стр.

    Символ перехода на новую строку учитывается.

    использовать Файлы П
    алг
    нач
    цел f, line, word, char, in, i
    лит s
    line := 0
    word := 0
    char := 0
    f := открыть на чтение ("текст.txt")
    нц пока не конец файла (f)
    Фввод f, s
    line := line + 1
    вывод s, нс
    char := char + длин(s)
    in := 0
    нц для i от 1 до длин(s)
    если s[i] " " и in = 0 то
    word := word + 1
    in := 1
    иначе
    если s[i] = " " то in := 0 все
    все
    кц
    кц
    закрыть(f)
    вывод нс, "строк - ", line, нс
    вывод "слов - ", word, нс
    вывод "символов - ", char
    кон

    Репутация: нет
    Всего: нет

    Как посчитать количество слов в файле?
    Если словом нужно считать то что отделено пробелами, enterom and Tab

    Вот посчитать количество символов можно, но вот как посчитать слова?

    Кто-нибудь встречался с ткой задачей?

    Язык програмирования Си.

    Репутация: нет
    Всего: нет

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

    Репутация: нет
    Всего: 3

    Репутация: 1
    Всего: 116

    дубликаты символов табуляции не должны подсчитываться. Если будет 10 пробелов подряд - не значит, что счетчик слов должен увеличиться на 10.

    Репутация: нет
    Всего: 3

    volvo877, понятное дело!
    Я же сказал, что самый простой вариант! Простой и очень критичный к содержимому файла! Двойное и более дублирование пробелов, символов новой строки и табуляции он не видит! А ещё. А ещё, если функция fgetc не сможет прочитать из потока символ, она вернёт EOF, что может послужить причиной недосчёта!

    Репутация: 45
    Всего: 134

    Самый простой вариант, который приходит в голову, это
    Цитата

    324324 32 444444444
    382844 4324 423
    333
    3
    3
    1

    Ну или более безопасный вариант

    int words=0;
    char c;

    Здесь был кролик. Но его убили.
    Человеки < кроликов, йа считаю.

    Репутация: 6
    Всего: 44

    Репутация: 45
    Всего: 134

    chaos
    Тогда уж ifs >> str
    Но в любом случае это С++, а не Си.

    ps. Даже вот так

    Здесь был кролик. Но его убили.
    Человеки < кроликов, йа считаю.

    Репутация: 6
    Всего: 44


    упс
    забыл убрать, сории за невнимательность
    и видимо по диаганали прочитал топик)) раз не заметил что на Си надо

    Репутация: 6
    Всего: 44

    вот еще один пример на этот раз на СИ(вроде как такая же идея была у KyKy)

    Репутация: нет
    Всего: нет

    Репутация: 5
    Всего: 29

    chaos, Mayk Прикольно, конечно, но. вроде автора темы уважать неплохо. Новичёк

    Репутация: нет
    Всего: нет

    Репутация: 0
    Всего: 12

    Перебирая по символу в цикле-
    если ((это первый символ И его код больше пробела) ИЛИ (код символа меньше или равен пробелу) ) уст флаг=1

    передвинуть указатель на следующий символ

    если (код символа больше пробела И флаг==1) инкрементировать счетчик слов

    Репутация: 6
    Всего: 44

    Enya
    Идея вообще такая: как только мы встретили символ код каторого меньш 33(те всякие там пробелы, переводы строк и тп дрянь) и перед этим кодом был символ(те код больше 32, определяем был ли символ или пробел через флаг fSpace) то можно сказать что кончилось слово

    Репутация: 45
    Всего: 134


    только тут надо учитывать, что если char трактуется как signed char (а так скорее всего и есть), то русские буквы и псевдографика(которые как известно имеют номера 0x80-0xFF) тоже будут меньше нуля.
    Здесь был кролик. Но его убили.
    Человеки < кроликов, йа считаю.

    Репутация: нет
    Всего: -4

    В позапрошлом семестре сделал людям кучу курсовиков, связанных со строками.
    Вот близкий тебе пример:

    Задание на курсовую работу :

    Написать программу, открывающую файл, подсчитывающую количество слов в нём и выводящую в некоторый другой файл строки, содержащие слово и количество вхождений слова в исходный файл. Строки должны быть упорядочены по длине слова.

    char *infName,*outfName,*strFText,*strTime,*strWords,chrAct;
    FILE *inFile,*outFile;
    int FLen,n,m,QW,*intPos,intTime;

    • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
    • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
    • Прежде чем задать вопрос, прочтите это и/или это! хранится весь мировой запас ссылок на документы, связанные с C++ :)
    • Не брезгуйте пользоваться тегами [code=cpp][/code].
    • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".

    Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

    [ Время генерации скрипта: 0.1529 ] [ Использовано запросов: 21 ] [ GZIP включён ]

    Мне нужно написать код на C, который выводит количество символов, строк и слов в данном файле. Задача кажется простой, но я действительно не уверен, что пошло не так в этот момент.

    Идея задачи заключается в том, что вывод должен быть таким же, как вывод команды wc в Linux. Но я совершенно не понимаю, почему в моем цикле пропускаются некоторые символы. То, как я написал код, должно позволять считать КАЖДЫЙ ОДИН символ, даже эти пробелы. Почему тогда моя программа показывает, что файл-образец содержит 65 символов, а wc показывает 68? Я подумал, что, возможно, есть какие-то символы, которые пропускает fgetc, но это невозможно, поскольку я использовал эту функцию раньше, когда писал программу для копирования содержимого одного текстового файла в другой, и все работало правильно.

    Кстати, мое решение для подсчета слов правильное? Условие после цикла должно гарантировать, что учитывается последнее слово перед EOF. Я использовал isspace, чтобы убедиться, что в финале нет пробелов.

    2 ответа

    "Моя программа показывает, что файл примера содержит 65 символов, а wc показывает 68"

    Вы работаете в Windows, и в вашем файле всего три строки? Если это так, проблема в том, что Windows сопоставляет окончания строк CRLF с символами новой строки, поэтому 3 пары CRLF сопоставляются с окончанием 3 строк (только LF) с учетом расхождения. Чтобы решить эту проблему, откройте файл в двоичном режиме.

    Я думаю, что код для подсчета слов в порядке, не запустив код. Вместо этого вы можете использовать флаг «in-word», изначально установленный на 0 (false), и переключиться на true и подсчитать новое слово, когда вы обнаружите что-то, что не является пробелом, когда вы не в слове. Оба работают; они немного разные.

    Также помните, что fgetc() и родственники возвращают int , а не char . Вы не можете надежно обнаружить EOF, если сохраните возвращаемое значение в char , хотя характер проблемы зависит от того, является ли простой char подписанным или беззнаковым, и от используемого набора кода.

    Если простой char является беззнаковым типом, вы никогда не сможете обнаружить EOF (поскольку EOF отображается в 0xFF, и когда он преобразуется в int для сравнения с EOF, он является положительным). Если простой char подписан, если входные данные содержат код 0xFF (в ISO 8859-1 и связанных наборах кодов это ÿ - ЛАТИНСКАЯ СТРОЧНАЯ БУКВА Y С ДИАРЕЗИСОМ в терминологии Unicode), вы обнаружите EOF раньше. Однако действительный UTF-8 никогда не может содержать байт 0xFF (ни 0xC0, 0xC1, ни 0xF5..0xFF), поэтому вы не должны сталкиваться с этой проблемой неверной интерпретации - но тогда ваш код является подсчетом байтов, а не подсчетом символов.

    меня спросили об этом во время интервью, и, по-видимому, это простой вопрос, но это не было и до сих пор не очевидно для меня.

    учитывая строку, подсчитайте все слова в ней. Не имеет значения, если они повторяются. Просто общее количество, как в текстовых файлах word count. Слова-это все, что отделено пробелом, и пунктуация не имеет значения, если это часть слова.

    например: A very, very, very, very, very big dog ate my homework. ==> 11 words

    мой "алгоритм" просто проходит через поиск пробелов и увеличиваю счетчик, пока не достигну нуля. Поскольку я не получил работу и меня попросили уйти после этого, я думаю, что мое решение не было хорошим? У кого-нибудь есть более умное решение? Я что-то упускаю?

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

    предполагая, что слова разделены пробелом:

    Примечание: между словами может быть несколько пробелов. Также это не ловит другие символы пробела, такие как tab new line или Carriage return. Поэтому подсчета пробелов недостаточно.

    оператор ввода потока >> при использовании для чтения строки из потока. Читает одно слово, разделенное пробелом. Поэтому они, вероятно, искали вас, чтобы использовать это для идентификации слов.

    когда можно использовать этот считать слова в строке.

    усложняется:
    Потоки можно обрабатывать так же, как и любой другой контейнер, и есть итераторы для цикла через них std::istream_iterator. Когда вы используете оператор ++ в istream_iterator, он просто читает следующее значение из потока, используя оператор >>. В этом случае мы читаем std:: string, поэтому он читает слово, разделенное пробелом.

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

    чтобы избежать копирования строки мы можем быть Sneaky:

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

    Читайте также: