2012-04-29 20 views
13

मेरे सी ++ कोड में, मैं एक टेक्स्ट फ़ाइल (* .txt) से पढ़ना चाहता हूं और प्रत्येक प्रविष्टि को टोकननाइज़ करना चाहता हूं। अधिक विशेष रूप से, मैं फ़ाइल से अलग-अलग शब्दों को पढ़ने में सक्षम होना चाहता हूं, जैसे कि "प्रारूप", "स्टैक", "जेसन", "यूरोप", आदिstd :: fstream के साथ टेक्स्ट फ़ाइल पढ़ने पर मैं गैर-डिफ़ॉल्ट डिलीमीटर का उपयोग कैसे कर सकता हूं?

मैं fstream उपयोग करने के लिए इस कार्य को करने के लिए चुना है, और मैं यह मेरे द्वारा उपयोग करना चाहते हैं (अंतरिक्ष, \n, साथ ही हाइफ़न और यहां तक ​​कि "Mcdonal के" में एपॉस्ट्रोफ़ी) को सीमांकक है स्थापित करने के लिए कैसे पता नहीं है। मुझे लगता है कि अंतरिक्ष और \n डिफ़ॉल्ट डिलीमीटर हैं, लेकिन हाइफ़न नहीं हैं, लेकिन मैं उन्हें डिलीमीटर के रूप में व्यवहार करना चाहता हूं ताकि फ़ाइल को पार्स करते समय, मुझे "ब्ला ब्ला xxx पशु - बिल्ली" में शब्दों को "ब्लाह" के रूप में प्राप्त किया जाएगा, "ब्लाह", "xxx", "पशु", "बिल्ली"।

है कि, मैं "स्टैक-अतिप्रवाह" से दो तार प्राप्त करने में सक्षम होना चाहता हूँ, "आप कर रहे हैं", आदि, और अभी भी एक ही समय में डिलीमीटर के रूप में \n और अंतरिक्ष को बनाए रखने में सक्षम हो।

+0

गेटलाइन (स्ट्रीम, चर, डिलीमीटर); –

+0

आप "पशु - बिल्ली" को फ़िल्टर करना चाहते हैं क्योंकि इसमें हाइफ़न हैं? यह मुझे टोकन करने की तरह नहीं लगता है। – Johnsyweb

+0

मैं उन्हें फ़िल्टर करने की कोशिश नहीं कर रहा हूं; मैं पशु और बिल्ली को दो अलग-अलग शब्दों के रूप में पढ़ने की कोशिश कर रहा हूं। – FrozenLand

उत्तर

16

डिलीमीटर के रूप में एक IStream व्यवहार करता है "श्वेत स्थान"। यह यह कहने के लिए एक लोकेल का उपयोग करता है कि कौन से पात्र सफेद स्थान हैं। एक लोकेल, बदले में, एक प्रकार facet शामिल है जो चरित्र प्रकारों को वर्गीकृत करता है।

#include <locale> 
#include <iostream> 
#include <algorithm> 
#include <iterator> 
#include <vector> 
#include <sstream> 

class my_ctype : public 
std::ctype<char> 
{ 
    mask my_table[table_size]; 
public: 
    my_ctype(size_t refs = 0) 
     : std::ctype<char>(&my_table[0], false, refs) 
    { 
     std::copy_n(classic_table(), table_size, my_table); 
     my_table['-'] = (mask)space; 
     my_table['\''] = (mask)space; 
    } 
}; 

और एक छोटे से परीक्षण कार्यक्रम यह काम करता है दिखाने के लिए: इस तरह के एक पहलू कुछ इस तरह दिख सकता है

int main() { 
    std::istringstream input("This is some input from McDonald's and Burger-King."); 
    std::locale x(std::locale::classic(), new my_ctype); 
    input.imbue(x); 

    std::copy(std::istream_iterator<std::string>(input), 
     std::istream_iterator<std::string>(), 
     std::ostream_iterator<std::string>(std::cout, "\n")); 

    return 0; 
} 

परिणाम:

This 
is 
some 
input 
from 
McDonald 
s 
and 
Burger 
King. 

istream_iterator<string>>> का उपयोग करता है व्यक्ति तार को पढ़ने के लिए धारा से, इसलिए यदि आप उन्हें सीधे उपयोग करते हैं, तो आपको एक ही परिणाम मिलना चाहिए। जिन हिस्सों को आप शामिल करना चाहते हैं वे लोकेल बना रहे हैं और स्ट्रीम को उस लोकेल का उपयोग करने के लिए imbue का उपयोग कर रहे हैं।

+0

तो क्या आप विजुअल स्टूडियो का उपयोग कर रहे हैं? मैंने कोड को विजुअल स्टूडियो (ठीक से) में रखा है और यह संकलित नहीं करता है ... – FrozenLand

+0

@ user1348863: हां, मैंने इसे विजुअल स्टूडियो 10 के साथ परीक्षण किया। –

+1

उत्कृष्ट! एनबी: [** 'std :: copy_n()' **] (http://en.cppreference.com/w/cpp/algorithm/copy_n) एक सी ++ 11ism है। पुराने कंपाइलरों को 'std :: copy (classic_table(), classic_table() + table_size, my_table) की आवश्यकता होगी;' (या समान)। – Johnsyweb

1

आप

istream::getline(char* buffer, steamsize maxchars, char delim) 

उपयोग कर सकते हैं, हालांकि यह केवल एक ही सीमांकक का समर्थन करता है। अपने अलग-अलग डिलीमीटर पर लाइनों को आगे विभाजित करने के लिए, आप

char* strtok(char* inString, const char* delims) 

का उपयोग कर सकते हैं जो कई डिलीमीटर लेता है। जब आप स्ट्रोकोक का उपयोग करते हैं तो आपको केवल अपने बफर के पते को पहली बार पास करने की आवश्यकता होती है - उसके बाद बस एक नल में गुजरती है और यह आपको आखिरी टोकन देता है जो आपको दिया गया है, जब कोई न हो तो एक नल पॉइंटर वापस कर देगा अधिक।

संपादित करें: एक विशिष्ट कार्यान्वयन होगा कुछ

तरह
char buffer[120]; //this size is dependent on what you expect the file to contain 
while (!myIstream.eofbit) //I may have forgotten the exact syntax of the end bit 
{ 
    myIstream.getline(buffer, 120); //using default delimiter of \n 
    char* tokBuffer; 
    tokBuffer = strtok(buffer, "'- "); 
    while (tokBuffer != null) { 
     cout << "token is: " << tokBuffer << "\n"; 
     tokBuffer = strtok(null, "'- "); //I don't need to pass in the buffer again because it remembers the first time I called it 
    } 
} 
+0

तो क्या आप अधिक विशिष्ट हो सकते हैं? मान लीजिए कि मैं स्टैक-ओवरफ्लो को दो अलग-अलग शब्दों के ढेर और ओवरफ्लो के रूप में पढ़ना चाहता हूं, मैं यह कैसे कर सकता हूं? (मुझे अभी भी अंतरिक्ष और \ n एक ही समय में delimiters के रूप में उपयोग करने की आवश्यकता है।) इसके अलावा, चलो चलो और चलो। धन्यवाद! – FrozenLand

+0

संपादित संस्करण \ n, ', -, और अंतरिक्ष पर टोकननाइज़ करना चाहिए। – QuantumRipple

+0

अच्छा लगता है, लेकिन क्या होगा यदि मेरी फ़ाइल * 1 एमबी का * .txt है? 120 के स्थान पर मैं क्या रखूं? – FrozenLand