Софтуерно Инженерство
Loading...
kaminka avatar kaminka 5 Точки

Разграничаване на string-ове от getline. Memory Management Homework

Здравейте,

Извинявам се предварително ако въпроса ми е прекалено елементарен, но наистина не мога да го направя това. А именно да отделя различните string-ове веднъж след като съм прочела някакъв текст от конзолата. Трябва да мина през всяка дума, за да променя или проверя нещо в упражнения 5,6 и 7. 

Знам че за getline може да се зададе опция да взема до определен символ. Но в случая това което ме обърква е, че не е един символа, който разделя думите. Може да е празно място, може да е тире, може да е запетя, може да е скоба и тн. 

Как се прави така че всички тези символи да бъдат отчетени като разграничения между думите?

Камелия

0
C++ Programming 16/03/2017 10:37:03
georgi.stef.georgiev avatar georgi.stef.georgiev 916 Точки
Best Answer

Здравей,

За тези три задачи не е нужно да третираш входа като отделни думи, които отделно трябва да обработваш. Можеш директно да работиш върху целия вход като един цял string (който идва от getline).

За 5-та задача - как би решила проблема, ако задачата беше просто за масив от числа, където трябва да изпечаташ всяко положително число, което е непосредствено след отрицателно число (или някакъв друг критерий за едно число последвано от друго число)? Как би я решила, ако вместо да го изпечатваш, трябваше да го промениш? Какво общо има "определен вид число последвано от определен вид друго число" с разпознаването на първата буква на дума? Edit: ако имаш нужда от още помощ тук, в демо 17 от лекцията има функция, която брои думи - как би я ползвала нея, за да смениш началото на думата да е главна буква, вместо да броиш?

За 6-та задача - тук изобщо не става въпрос за отделни думи, просто трябва да преброиш колко пъти някакъв текст се среща. Трябва да направиш find-а, който браузърите и текстовите редактори правят, когато натиснеш Ctrl-F. Виж примера, какво значение би имало за него дали има space-ове (или каквото и да е) между думите? Как можеш да търсиш нещо в string със C++?

За 7-ма задача - подобно на 6-та, но трябва да последваш намирането със заместване. Тоест по някакъв начин трябва да промениш стария стринг, така че да запази всички символи освен тези на позициите, на които заместваш. Също така трябва да внимаваш с дължините - ако заместващия текст е по-кратък, общата дължина на стринга ще намалее, и обратно.

Помисли върху тези неща и пробвай отново да намериш решение. Иначе със C++ няма лесен вграден начин да разделяш думи по множество разделители. Един вариант е да запишеш входа в един stringstream и след това да ходиш символ по символ, пазейки каквото си взела до момента в друг stringstream. В момента, в който срещнеш някой разделител (тоест ще проверяваш всеки символ поотделно), това което си запазила до момента като символи е дума - можеш да я запазиш някъде, можеш да я обработиш по някакъв желан начин и т.н. Но това не е нужно за решението на която и да е от тези задачи :)

Поздрави,

Жоро

0
16/03/2017 11:32:11
kaminka avatar kaminka 5 Точки

Благодаря ти за отговора! 

Имам още един въпрос за задача 5. Защо toupper не се задейства като е в функцията? Нещо не правя както трябва сигурно. Пробвах го в main и си работи, но в makeTitleCases не ми се получава:

#include<iostream>
#include <string>

using namespace std;

void makeTitleCase(string& text);

int main()
{
    cout << "Please enter a line of text:" << endl;

    string inputLine;
    getline(cin, inputLine);

    makeTitleCase(inputLine);

    cout << inputLine << endl;

    return 0;
}

void makeTitleCase(string& text)
{
    for(int i=0; i<text.length(); i++){
        if(text[i] == ' ' || text[i]== ','){
            toupper(text[i+1]);
        }
    }

    return;
}

0
georgi.stef.georgiev avatar georgi.stef.georgiev 916 Точки

Провери го как е дефиниран и описан тук: http://www.cplusplus.com/reference/cctype/toupper/

Забележи, че не приема референция към променлива, а взема стойност и връща стойност :)

Това означава, че ако имаш char letter = 'a'; toupper(letter) няма да направи нищо директно. Но ако имаш char letter = 'a'; char uppercaseLetter = toupper(a) вече е друго нещо. Също както abs(-5) няма да промени -5 на 5, а ще ти върне ново число, което е абсолютната стойност, така и toupper връща стойност вместо да променя това, което си му подала. http://www.cplusplus.com/ is your friend за всякакви такива неща

0
gydigydi avatar gydigydi 12 Точки

text[i+1]=toupper(text[i+1]);

Така ще работи обаче не работи за първата буква.

Освен интервал и ","  има още доста неща "  ' ? ....12345  и т.н.

Може да използваш isalpha().

0
16/03/2017 18:50:26
georgi.stef.georgiev avatar georgi.stef.georgiev 916 Точки

Освен съвета на колегата - помисли за последния символ - какво ще стане като направиш i+1 там? В конкретния случай, понеже работиш със string, а той има null-terminator накрая, ще си ок, но ако кодът ти правеше нещо различно от toupper може да бъде опасно :)

0
zzerro avatar zzerro 11 Точки

Аз го направих по този начин. Просто ползвам !isalpha(), т.е. всичко, което не е буква пред намерената буква. Сложил съм и проверка за интервал и нов ред.. За първия символ съвсем отделна проверка правя.

void makeTitleCase(string& text)
{
    int i = 0;
    if (isalpha(text[i])) toupper(text[i]); // Make upper if is a letter at index 0.

    for (i; i < text.length(); i++)
    {
        if (isalpha (text[i])                // Check for letter
            && (!isalpha (text[i-1])    // and any not-letter character
            || isspace(text[i-1])))         // or space/tab... etc. before before letter

            text[i] = toupper(text[i]);
    }
}


Нали функцията ти е void, защо има return? Работи ли ти с returna?

0
georgi.stef.georgiev avatar georgi.stef.georgiev 916 Точки

Можеш да имаш return; във void функция, стига да е "празен", тоест да няма нещо което return-ваш. Принципно идеята е да можеш да прекратиш изпълнението на функцията, преди тя да е стигнала до края си (примерно в някой if), доста често се ползва (в другите езици е същото). Не е задължително да го има и общо взето в нейния пример няма нужда от него, защото така или иначе е накрая, но не е грешно и не пречи :)

0
zzerro avatar zzerro 11 Точки

аха! Нещо като break за фунцкия. Не знаех, че може да е празен... (аз го пробвах с нула, ама не ставаше...)

Хубаво е, че си така отзивчив и всеки път човек научава нещо!

0
georgi.stef.georgiev avatar georgi.stef.georgiev 916 Точки

Да, точно като break за функция. И е по-"силно" от break-а, тоест ако си в цикъл във функция, ако кажеш break ще излезе от цикъла, ако кажеш return направо ще излезе от функцията.

Радвам се, че съм от полза :)

0
gydigydi avatar gydigydi 12 Точки

Според мен ти трябва едно i++ преди цикъла или в самия цикъл for (++i;..... .

Какво ще ти даде && (!isalpha (text[i-1])   от i=0 ? Божа работа...

0
16/03/2017 21:37:52
Bobosam avatar Bobosam 184 Точки

Гледам, че от C++ 11 вече има std::regex_match. Не съм го пробвал но като знам как работят регексите не би трябвало да е проблем разделянето на думи.

0
zzerro avatar zzerro 11 Точки

Просто може цикълът да започва от 1. Нулата така или иначе е вече проверена. Не ме притеснява какво ще намери на -1. Каквото и да намери, първият символ ще си остане главна буква. Условието не е да сваляме съществуващите в текста главни букви...

0
zzerro avatar zzerro 11 Точки

Хубаво е с хораsmiley

0
gydigydi avatar gydigydi 12 Точки

Притеснява, не притеснява...Това е математика. 2 пъти проверяваш 1вата буква, един път извън цикъла и втори път в цикъла. Така ли е? Какъв е смисъла да я проверяваш 2 пъти?

И 2рата проверка е научно казано ундефинед. Да кажат знаещите.

И не си мисли че се заяждам с тебе. Аз също се уча.

 

0
17/03/2017 01:41:17
kaminka avatar kaminka 5 Точки

georgi.stef.georgiev Още веднъж мерси. Много е приятно като има кой да помогне и да обясни :)

0
zzerro avatar zzerro 11 Точки

Здравей @ Bobosam !

Опитвах да използвам regex_replace, ама срещнах 2 проблема:

Много е бавно. Нямам изпълнение под 3 сек., а условието е до 0,1 сек.

Другият проблем е, че ме праща в някакви хедъри. Дали е от настройките на компилатора ми или грешно го използвам:

...

string text = "kid+ding kitt!ens W123456";

ostringstream separatedWords;

regex toReplace(".|,|;|!|?");
regex_replace(separatedWords, text.begin(), text.end(), toReplace, " ");

0