2011-05-27 17 views
5

के रूप में वर्गीकृत करने इस सवाल का जो अपेक्षाकृत जल्दी ही बंद हो गया के आधार पर:
Trying to create a program to read a users input then break the array into seperate words are my pointers all valid?कैसे tokenize करने के लिए (शब्द) विराम चिह्न अंतरिक्ष

बल्कि बंद करने से मुझे लगता है कि कुछ अतिरिक्त काम ओपी की मदद करने के प्रश्न को स्पष्ट करने के लिए में चले गए हैं सकता है।

प्रश्न:

मैं उपयोगकर्ता इनपुट tokenize और शब्दों की एक सरणी में टोकन संग्रहीत करना चाहते हैं।
मैं विराम चिह्न (।, -) को डिलीमीटर के रूप में उपयोग करना चाहता हूं और इस प्रकार इसे टोकन स्ट्रीम से हटा दिया।

सी में मैं टोकन में सरणी तोड़ने के लिए strtok() का उपयोग करता हूं और फिर मैन्युअल रूप से एक सरणी बनाता हूं।
इस तरह:

मुख्य समारोह:

char **findwords(char *str); 

int main() 
{ 
    int  test; 
    char words[100]; //an array of chars to hold the string given by the user 
    char **word; //pointer to a list of words 
    int  index = 0; //index of the current word we are printing 
    char c; 

    cout << "die monster !"; 
    //a loop to place the charecters that the user put in into the array 

    do 
    { 
     c = getchar(); 
     words[index] = c; 
    } 
    while (words[index] != '\n'); 

    word = findwords(words); 

    while (word[index] != 0) //loop through the list of words until the end of the list 
    { 
     printf("%s\n", word[index]); // while the words are going through the list print them out 
     index ++; //move on to the next word 
    } 

    //free it from the list since it was dynamically allocated 
    free(word); 
    cin >> test; 

    return 0; 
} 

लाइन tokenizer:

char **findwords(char *str) 
{ 
    int  size = 20; //original size of the list 
    char *newword; //pointer to the new word from strok 
    int  index = 0; //our current location in words 
    char **words = (char **)malloc(sizeof(char *) * (size +1)); //this is the actual list of words 

    /* Get the initial word, and pass in the original string we want strtok() * 
    * to work on. Here, we are seperating words based on spaces, commas, * 
    * periods, and dashes. IE, if they are found, a new word is created. */ 

    newword = strtok(str, " ,.-"); 

    while (newword != 0) //create a loop that goes through the string until it gets to the end 
    { 
     if (index == size) 
     { 
      //if the string is larger than the array increase the maximum size of the array 
      size += 10; 
      //resize the array 
      char **words = (char **)malloc(sizeof(char *) * (size +1)); 
     } 
     //asign words to its proper value 
     words[index] = newword; 
     //get the next word in the string 
     newword = strtok(0, " ,.-"); 
     //increment the index to get to the next word 
     ++index; 
    } 
    words[index] = 0; 

    return words; 
} 

ऊपर कोड पर किसी भी टिप्पणी की सराहना की जाएगी।
लेकिन, इसके अलावा, सी ++ में इस लक्ष्य को प्राप्त करने के लिए सबसे अच्छी तकनीक क्या है?

+0

'सीन >> टेस्ट' के अलावा, अंत में, मैं इस सी ++ कोड को कॉल नहीं करूंगा। आप स्पष्ट रूप से सी तकनीकों का उपयोग कर रहे हैं। आधुनिक सी ++ का उपयोग करके ऐसा करना ** बहुत ** अलग होगा। –

+0

वैसे भी यदि आप सी संस्करण के साथ जाने का फैसला करते हैं, तो आपके पास संभावित भारी मेमोरी रिसाव है (जब आप आकार बदलते हैं), और यदि ऐसा होता है, तो आप पुरानी सामग्री (कचरा पॉइंटर्स लौटाने) पर प्रतिलिपि नहीं बनाते हैं। शायद आप malloc के बजाय realloc का उपयोग करना चाहते थे? cource के बारे में मैं आपको सी ++ मार्ग के साथ जाने के लिए सलाह दूंगा, जहां आप पहले ही कुछ सलाह प्राप्त कर चुके हैं, इसलिए आपको इस तरह की पुरानीस्कूल सी समस्याओं से निपटना नहीं होगा;) – Shaggi

+0

@Shaggi: मुझे यकीन है कि मूल प्रश्न का मूल लेखक क्या है। लेकिन जैसा कि आप कहते हैं कि सबसे अच्छा तरीका सी –

उत्तर

5

पहले से ही बहुत सारे प्रश्नों से ढंका हुआ है कि सी ++ में स्ट्रीम को कैसे टोकन करना है।
उदाहरण:

मूल रूप से strtok() तो आप उपयोगकर्ता निर्धारित पात्रों की एक पूरी गुच्छा पर स्ट्रिंग को विभाजित करने की अनुमति देता है, जबकि: How to read a file and get words in C++

लेकिन क्या कठिन है खोजने के लिए कैसे() strtok रूप में एक ही कार्यक्षमता प्राप्त है सी ++ स्ट्रीम आपको केवल white space को विभाजक के रूप में उपयोग करने की अनुमति देता है। सौभाग्य से white space की परिभाषा लोकेल द्वारा परिभाषित की गई है ताकि हम स्थान के रूप में अन्य पात्रों के इलाज के लिए लोकेल को संशोधित कर सकें और इससे हमें धारा को और अधिक प्राकृतिक फैशन में टोकननाइज़ करने की अनुमति मिल जाएगी।

#include <locale> 
#include <string> 
#include <sstream> 
#include <iostream> 

// This is my facet that will treat the ,.- as space characters and thus ignore them. 
class WordSplitterFacet: public std::ctype<char> 
{ 
    public: 
     typedef std::ctype<char> base; 
     typedef base::char_type  char_type; 

     WordSplitterFacet(std::locale const& l) 
      : base(table) 
     { 
      std::ctype<char> const& defaultCType = std::use_facet<std::ctype<char> >(l); 

      // Copy the default value from the provided locale 
      static char data[256]; 
      for(int loop = 0;loop < 256;++loop) { data[loop] = loop;} 
      defaultCType.is(data, data+256, table); 

      // Modifications to default to include extra space types. 
      table[','] |= base::space; 
      table['.'] |= base::space; 
      table['-'] |= base::space; 
     } 
    private: 
     base::mask table[256]; 
}; 

हम तो इस तरह एक स्थानीय में इस पहलू का उपयोग कर सकते हैं:

std::ctype<char>* wordSplitter(new WordSplitterFacet(std::locale())); 

    <stream>.imbue(std::locale(std::locale(), wordSplitter)); 

अपने प्रश्न के अगले भाग कैसे मैं एक सरणी में इन शब्दों की दुकान होगी। खैर, सी ++ में आप नहीं करेंगे। आप इस कार्यक्षमता को std :: vector/std :: स्ट्रिंग में प्रतिनिधि देंगे। अपना कोड पढ़कर आप देखेंगे कि आपका कोड कोड के उसी हिस्से में दो प्रमुख चीजें कर रहा है।

  • यह स्मृति का प्रबंधन कर रहा है।
  • यह डेटा टोकन करना है।

बुनियादी सिद्धांत Separation of Concerns है जहां आपका कोड केवल दो चीजों में से एक को प्रयास करना चाहिए और करना चाहिए। इसे या तो संसाधन प्रबंधन (इस मामले में स्मृति प्रबंधन) करना चाहिए या इसे व्यापार तर्क (डेटा का टोकननाइज़ेशन) करना चाहिए। कोड के विभिन्न हिस्सों में इन्हें अलग करके आप कोड को अधिक सामान्य रूप से उपयोग करना और लिखना आसान बनाते हैं। सौभाग्य से इस उदाहरण में सभी संसाधन प्रबंधन पहले से ही std :: vector/std :: स्ट्रिंग द्वारा किया जाता है जिससे हम व्यापार तर्क पर ध्यान केंद्रित कर सकते हैं।

जैसा कि कई बार दिखाया गया है कि स्ट्रीम को टोकननाइज़ करने का आसान तरीका ऑपरेटर >> और एक स्ट्रिंग का उपयोग कर रहा है। यह धारा को शब्दों में तोड़ देगा। फिर आप धारावाहिक को स्ट्रीम करने के लिए स्वचालित रूप से लूप को स्वचालित रूप से लूप करने के लिए उपयोग कर सकते हैं।

std::vector<std::string> data; 
for(std::istream_iterator<std::string> loop(<stream>); loop != std::istream_iterator<std::string>(); ++loop) 
{ 
    // In here loop is an iterator that has tokenized the stream using the 
    // operator >> (which for std::string reads one space separated word. 

    data.push_back(*loop); 
} 

अगर हम कोड को आसान बनाने के लिए कुछ मानक एल्गोरिदम के साथ इस गठबंधन।

std::copy(std::istream_iterator<std::string>(<stream>), std::istream_iterator<std::string>(), std::back_inserter(data)); 

अब एक भी आवेदन

int main() 
{ 
    // Create the facet. 
    std::ctype<char>* wordSplitter(new WordSplitterFacet(std::locale())); 

    // Here I am using a string stream. 
    // But any stream can be used. Note you must imbue a stream before it is used. 
    // Otherwise the imbue() will silently fail. 
    std::stringstream teststr; 
    teststr.imbue(std::locale(std::locale(), wordSplitter)); 

    // Now that it is imbued we can use it. 
    // If this was a file stream then you could open it here. 
    teststr << "This, stri,plop"; 

    cout << "die monster !"; 
    std::vector<std::string> data; 
    std::copy(std::istream_iterator<std::string>(teststr), std::istream_iterator<std::string>(), std::back_inserter(data)); 

    // Copy the array to cout one word per line 
    std::copy(data.begin(), data.end(), std::ostream_iterator<std::string>(std::cout, "\n")); 
} 
+0

+1। यह मेरा बहुत ही समान है: http://stackoverflow.com/questions/5607589/right-way-to-split-an-stdstring-into-a-vectorstring – Nawaz

6

एक strtok() से इतना एक सी में बेहतर है कुछ के लिए boost tokenizer पर नज़र ++ संदर्भ है में संयोजन सब से ऊपर।

+0

+1 'कारण मैंने इसका उत्तर दिया होगा! – juanchopanza

+0

+1: व्यक्तिगत रूप से मुझे लगता है कि धाराओं का लोकेल हिस्सा मानक का सबसे कम उपयोग हिस्सा है और अधिक लोगों को इसे सीखना चाहिए। लेकिन दूसरी तरफ उन्हें इसे सीखना चाहिए ताकि हम बूस्ट टोकनेज़र जैसे बेहतर अबास्ट्रक्शन कर सकें (ऐसा नहीं है कि मैं कह रहा हूं कि बूस्ट टोकननाइज़र कैसे काम करता है)। –

संबंधित मुद्दे