2008-09-22 2 views
8

Хорошо, прежде чем я даже задал свой вопрос, я хочу сделать одно ясно. В настоящее время я студент NIU по информатике, и это относится к одному из моих заданий для класса. Поэтому, если у кого-то есть проблема, не читайте дальше и просто продолжайте рассказывать о своем бизнесе.Очистка строки пунктуации в C++

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

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

Так что я ищу две вещи, любые предложения о том, как я мог это сделать) исправить это, просто просто стирая его, и б) любые улучшения, которые я мог бы внести в код, который я уже написал.

Вот функции, которые я написал для чтения из файла, а затем тот, который его очищает.

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

Редактировать: Спасибо Крис. Номера разрешены :). Если у кого-то есть улучшения в коде, который я написал, или какой-либо критике чего-то, что я сделал, я буду слушать. В школе мы действительно не возвращаемся к правильному, правильному или эффективному способу делать что-то.

int get_words(map<string, int>& mapz) 
{ 
int cnt = 0;    //set out counter to zero 

map<string, int>::const_iterator mapzIter; 

ifstream input;   //declare instream 
input.open("prog2.d"); //open instream 
assert(input);   //assure it is open 

string s;     //temp strings to read into 
string not_s; 

input >> s; 

while(!input.eof())  //read in until EOF 
    { 
    not_s = ""; 
    clean_entry(s, not_s); 

    if((int)not_s.length() == 0) 
    { 
    input >> s; 
    clean_entry(s, not_s); 
    }  

    mapz[not_s]++;    //increment occurence 
    input >>s; 
    } 
input.close();  //close instream 

for(mapzIter = mapz.begin(); mapzIter != mapz.end(); mapzIter++) 
    cnt = cnt + mapzIter->second; 

return cnt;  //return number of words in instream 
} 


void clean_entry(const string& non_clean, string& clean) 
{ 
int i, j, begin, end; 

for(i = 0; isalnum(non_clean[i]) == 0 && non_clean[i] != '\0'; i++); 

begin = i; 

if(begin ==(int)non_clean.length()) 
    return; 

for(j = begin; isalnum(non_clean[j]) != 0 && non_clean[j] != '\0'; j++); 

end = j; 

clean = non_clean.substr(begin, (end-begin)); 

for(i = 0; i < (int)clean.size(); i++) 
    clean[i] = tolower(clean[i]); 

} 
+0

Оплачено для полного раскрытия – 2008-09-22 18:10:45

+0

То же самое здесь. Я также признателен, что Брэндон, очевидно, приложил много усилий к его работе, прежде чем задавать вопрос. – 2008-09-22 18:15:28

+0

У меня нет проблем с кем-то, просящим о помощи по домашнему заданию, когда они сначала попытались выполнить его. Это ленивые люди, которые просят нас сделать всю свою работу за них, которые раздражают меня. – 2008-09-22 18:22:00

ответ

7

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

not_s = ""; 
clean_entry(s, not_s); 

if((int)not_s.length() == 0) 
{ 
    input >> s; 
    clean_entry(s, not_s); 
}  

mapz[not_s]++;    //increment occurence 
input >>s; 

в

not_s = ""; 
clean_entry(s, not_s); 

if((int)not_s.length() > 0) 
{ 
    mapz[not_s]++;    //increment occurence 
}  

input >>s; 

EDIT: Я заметил, что вы проверяете, если символы являются буквенно-цифровыми. Если номера не разрешены, вам может потребоваться вернуться к этой области.

1

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

if (!not_s.empty()) 
    mapz[not_s]++; 

Стиль-мудрый, есть несколько вещей, которые я бы изменить, было бы вернуться очищенными от clean_entry вместо его модификации :

string not_s = clean_entry(s); 
... 
string clean_entry(const string &non_clean) 
{ 
    string clean; 
    ... // as before 
    if(begin ==(int)non_clean.length()) 
     return clean; 
    ... // as before 
    return clean; 
} 

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

2

Дальнейшее улучшение было бы

  • объявлять переменные только тогда, когда вы используете их, и в самом внутреннем объеме
  • использование C++ - стиль ставит вместо C-стиля (межд) бросает
  • использование пустой() вместо длины() == 0 сравнения
  • использовать оператор инкремента префикс для итераторов (т.е. ++mapzIter)
1

Функция 'getWords' выполняет множество различных действий, которые можно разделить на другие функции. Есть хороший шанс, что, разделив его на отдельные части, вы бы нашли ошибку самостоятельно.

Из основного состава, я думаю, вы могли бы разделить код на (по крайней мере):

  • getNextWord: Возвращение на следующий (не пустой) слово из потока (возвращает ложь, если нет ни слева)
  • clean_entry: Что у вас есть сейчас
  • getNextCleanWord: вызывает getNextWord, и если «true» вызывает CleanWord. Возвращает «false», если не осталось слов.

Подписи «getNextWord» и «getNextCleanWord» может выглядеть примерно так:

bool getNextWord (std::ifstream & input, std::string & str); 
bool getNextCleanWord (std::ifstream & input, std::string & str); 

Идея заключается в том, что каждая функция делает меньшую отчетливее часть проблемы. Например, 'getNextWord' ничего не делает, кроме как получить следующее не пустое слово (если оно есть). Таким образом, эта меньшая часть становится более простой частью проблемы для решения и отладки при необходимости.

Основной компонент «getWords», то можно упростить до:

std::string nextCleanWord; 
while (getNextCleanWord (input, nextCleanWord)) 
{ 
    ++map[nextCleanWord]; 
} 

Важным аспектом развития, ИМХО, это попытаться Разделяй и властвуй проблему. Разделите его на отдельные задачи, которые необходимо выполнить. Эти подзадачи будут более легкими для завершения, а также должны быть проще поддерживать.

Смежные вопросы