Loading...
Jovanna avatar Jovanna 186 Точки

strtok() сплитване по делимитери - въпрос

Здравейте,

искам да прехвърля стринг от вход към char arr[] и да махна делимитерите със strtok() , но да запазя празните позиции (strtok() работи с char arr[])

Стринга се въвежда от потребителя и е с варираща дължина.

Първият проблем, който срещнах, е , че не ми приема размер на char_array[] който не е const. Има ли хитър начин да не се инициализира c-string-а с толкова голям размер?

Вторият ми въпрос е: защо стрингът newLine си остава празен по-долу в кода? 

 
            const int char_arr_size_MAX = 500;


main() {
            char char_array[char_arr_size_MAX]{0};            
            for (int i = 0; i < line.size(); i++)
            {               
                char_array[i] = line[i];                
            }

            char * pnewCharArrNoDelimiters;
            pnewCharArrNoDelimiters = strtok(char_array, ",.-");   //пойнтер към първия елемент
      
            string newLine;
           
            while (pnewCharArrNoDelimiters != NULL)
            {

            newLine += *pnewCharArrNoDelimiters;    

           //дереференцирам, за да вкарам елемента в стринга, но не се получава

           //-------->  тук newLine си остава празен стринг след присвояването на стойността на първата позиция, защо?     

              
                pnewCharArrNoDelimiters = strtok(NULL, ",.-");               

             }

Тагове:
1
C++ Programming
MartinPaunov avatar MartinPaunov 77 Точки

Здравей,

Не съм сигурен, че правилно разбрах какво точно искаш да направиш, но като цяло не е необходимо да дереференцираш пойтера, тък като искаш да запишеш цялата последователност от символи в интервала между началото на текста и първият срещнат символ от изброените. Премахни дереференцирането и newLine ще се напълни както очакваш. 

Относно това дали можеш да инициализираш масив без да използваш предваритено зададена константа зависи от това какъв компилатор използваш някои компилатори ще ти позволят други не. Например Visual C++ компилатора няма да ти позволи да създадеш масива по следния начин: 

char char_array[line.size()];

Горното ще работи в CodeBlocks, който използва mingw компилатор.

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

char * char_array;
char_array = new char[line.size()];

Това ще работи и при Visual C++ компилатора, но после трябва да изтриеш паметта в края на обсега където се използва

delete []char_array;

Друга опция е да използваш smart pointer от С++ 11 стандарта, като това ти гарантира, че паметта ще бъде изтрита при излизането на масива от scope.

shared_ptr<char[]> char_array(new char[line.size()]);

Специално за shared_ptr - не съм напълно сигурен дали не освобождава паметта от С++ 17 стандарта, но съм почти сигурен, че unique_ptr ще работи както трябва дори и за компилатор със С++ 11.

Друг начин да разделиш текста по изброените символи за който се сещам е с използването на регулярен израз, като в този случай не ти е необходим char arr[] - масив, пример:

regex splitRegex ("([,.-]+)");

string newLine = regex_replace(line, splitRegex, "");

Горното не е точно сплитване, но зависи какво точно ти трябва можеш да промениш стринга с който се замества (може да не е празен стринг -> "", а да е спейс -> " " и т.н.т.), можеш да разгледаш и други примери в интернет.

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

Поздрави

3
24/05/2018 19:09:54
Jovanna avatar Jovanna 186 Точки

Благодаря!!

много хубаво инфо за различните начини, това ми трябваше!!!

meanwhile успях да се преборя със strtok() за да събирам в нов стринг само отделни числа / думи, без разделителите, но с празна позиция между тях (за по-нататъшна обработка), получи се много красиво, с два вложени while() :-)  ето:

string line;
getline(cin, line);
char char_array[char_arr_size_MAX]{0};    //const int char_arr_size_MAX = 500;  //така го бях написала и не ми се сменяше, но ще го пробвам и с динамичната памет
   
   for (int i = 0; i < line.size(); i++)
   {  
    char_array[i] = line[i];    
   }
   char * pnewCharArrNoDelimiters;
   char * arrBegin = char_array;
   pnewCharArrNoDelimiters = strtok(char_array, ",.-");
   
   string newLine;
     
   int k = 1;
   while (k < line.size())
   {   
    newLine += " ";  //за да се разделят отделните числа или думи
       while (pnewCharArrNoDelimiters != NULL)
       {
                newLine += *pnewCharArrNoDelimiters;
                pnewCharArrNoDelimiters = strtok(char_array + k, ",.-"); 
     //pnewCharArrNoDelimiters е NULL като дойде делимитер; Излиза от вътрешния цикъл; местя k  и

    //новата стойност на pnewCharArrNoDelimiters Е пойнтер към следващото парче от char arr[], СЛЕД ДЕЛИМИТЕРИТЕ !!!
     //вече не е NULL и влиза пак във вътрешния цикъл, да добави следващото парче ДО делимитер
                k++;
          }
    pnewCharArrNoDelimiters = strtok(char_array + k, ",.-");
    int difference = pnewCharArrNoDelimiters - arrBegin;
    k = difference + 1;
   }

Примерен вход: 34,,,,,....567,   ...---89 

Изход: 34 567 89

Поздрави!

1
26/05/2018 01:03:13
Можем ли да използваме бисквитки?
Ние използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Можете да се съгласите с всички или част от тях.
Назад
Функционални
Използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Използваме „сесийни“ бисквитки, за да Ви идентифицираме временно. Те се пазят само по време на активната употреба на услугите ни. След излизане от приложението, затваряне на браузъра или мобилното устройство, данните се трият. Използваме бисквитки, за да предоставим опцията „Запомни Ме“, която Ви позволява да използвате нашите услуги без да предоставяте потребителско име и парола. Допълнително е възможно да използваме бисквитки за да съхраняваме различни малки настройки, като избор на езика, позиции на менюта и персонализирано съдържание. Използваме бисквитки и за измерване на маркетинговите ни усилия.
Рекламни
Използваме бисквитки, за да измерваме маркетинг ефективността ни, броене на посещения, както и за проследяването дали дадено електронно писмо е било отворено.