2009-10-26 19 views
5

निम्नलिखित कोड समय में एक चरित्र को एक पाठ फ़ाइल पढ़ता है और stdout में इसे प्रिंट:खोजें

#include <stdio.h> 

int main() 
{ 
    char file_to_open[] = "text_file.txt", ch; 
    FILE *file_ptr; 

    if((file_ptr = fopen(file_to_open, "r")) != NULL) 
    { 
     while((ch = fgetc(file_ptr)) != EOF) 
     { 
      putchar(ch); 
     } 
    } 
    else 
    { 
     printf("Could not open %s\n", file_to_open); 
     return 1; 
    } 
    return(0); 
} 

लेकिन मुद्रण के बजाय stdout करने के लिए [putchar (ch)] मैं चाहता हूँ किसी अन्य टेक्स्टफाइल अर्थात् विशिष्ट स्ट्रिंग्स के लिए फ़ाइल को खोजें। strings.txt और आउटपुट मैच के साथ लाइन out.txt को

text_file.txt:

 
1993 - 1999 Pentium 
1997 - 1999 Pentium II 
1999 - 2003 Pentium III 
1998 - 2009 Xeon 
2006 - 2009 Intel Core 2 

strings.txt:

 
Nehalem 
AMD Athlon 
Pentium 

इस मामले text_file.txt के तीन पहले लाइनों से मेल खाएंगे में। मैंने सी में फाइल ऑपरेशंस पर कुछ शोध किया है, और ऐसा लगता है कि मैं उस समय एक चरित्र को fgetc [जैसे मैं अपने कोड में करता हूं], fgets के साथ एक पंक्ति और fread के साथ एक ब्लॉक, लेकिन मुझे लगता है कि कोई शब्द नहीं मेरी स्थिति में सही होगा?

+3

कारण है कि आप इस कार्यक्रम के लिए लिख रहे हैं ?! ऐसा करने के लिए grep/awk/sed का प्रयोग करें। –

+0

नहीं, टिम। टैग खोज के लिए हैं। कोई भी इसके लिए खोज नहीं करेगा। – GManNickG

+1

हां, मैं मानक यूनिक्स उपकरण के साथ जानता हूं, मैं सेकंड के मामले में इसे हल कर सकता हूं, लेकिन यह सी फाइल आईओ की गहरी समझ प्राप्त करना है। –

उत्तर

7

मुझे लगता है कि यह एक सीखने का अभ्यास है और आप बस शुरू करने के लिए एक जगह की तलाश में हैं। अन्यथा, आपको पहिया को फिर से नहीं बदला जाना चाहिए।

नीचे दिया गया कोड आपको इसमें शामिल होने का एक विचार देना चाहिए। यह एक ऐसा प्रोग्राम है जो आपको खोजी जाने वाली फ़ाइल का नाम निर्दिष्ट करने और उस फ़ाइल में खोजने के लिए एक तर्क देने की अनुमति देता है। वाक्यांशों को सरणी में एक सरणी में खोजने के लिए इसे संशोधित करने में सक्षम होना चाहिए और जांचें कि उस सरणी में से किसी भी शब्द को पढ़ने वाली किसी भी पंक्ति में दिखाई देता है या नहीं।

आप जो मुख्य कार्य खोज रहे हैं वह strstr है।

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

#ifdef DEBUG 
#define INITIAL_ALLOC 2 
#else 
#define INITIAL_ALLOC 512 
#endif 

char * 
read_line(FILE *fin) { 
    char *buffer; 
    char *tmp; 
    int read_chars = 0; 
    int bufsize = INITIAL_ALLOC; 
    char *line = malloc(bufsize); 

    if (!line) { 
     return NULL; 
    } 

    buffer = line; 

    while (fgets(buffer, bufsize - read_chars, fin)) { 
     read_chars = strlen(line); 

     if (line[read_chars - 1] == '\n') { 
      line[read_chars - 1] = '\0'; 
      return line; 
     } 

     else { 
      bufsize = 2 * bufsize; 
      tmp = realloc(line, bufsize); 
      if (tmp) { 
       line = tmp; 
       buffer = line + read_chars; 
      } 
      else { 
       free(line); 
       return NULL; 
      } 
     } 
    } 
    return NULL; 
} 

int 
main(int argc, char *argv[]) { 
    FILE *fin; 
    char *line; 

    if (argc != 3) { 
     return EXIT_FAILURE; 
    } 

    fin = fopen(argv[1], "r"); 

    if (fin) { 
     while (line = read_line(fin)) { 
      if (strstr(line, argv[2])){ 
       fprintf(stdout, "%s\n", line); 
      } 
      free(line); 
     } 
    } 

    fclose(fin); 
    return 0; 
} 

नमूना उत्पादन:

 
E:\Temp> searcher.exe searcher.c char 
char * 
    char *buffer; 
    char *tmp; 
    int read_chars = 0; 
    char *line = malloc(bufsize); 
    while (fgets(buffer, bufsize - read_chars, fin)) { 
     read_chars = strlen(line); 
     if (line[read_chars - 1] == '\n') { 
      line[read_chars - 1] = '\0'; 
       buffer = line + read_chars; 
main(int argc, char *argv[]) { 
    char *line; 
+0

यह बहुत दिलचस्प लग रहा है। आप सही ढंग से मान रहे हैं, यह मेरे लिए एक सीखने का अभ्यास है, और मैं देख सकता हूं कि स्रोत में ऐसे तत्व शामिल हैं जिन्हें मैंने पहले काम किया था, इसलिए मुझे इस कोड को पूरी तरह से समझने में सक्षम होना चाहिए। –

+0

मैं सी कोड के लिए बिल्कुल नया हूं लेकिन मैंने पूरी तरह से read_line फ़ंक्शन कॉल को fgets फ़ंक्शन कॉल और मुख्य फ़ंक्शन में आवंटित चार * रेखा को मनमाने ढंग से बड़ी संख्या में बदल दिया है क्योंकि fgets '\ n' वर्ण पर रुक जाता है। क्या आप शायद read_line फ़ंक्शन के इच्छित उद्देश्य को समझा सकते हैं? ऐसा लगता है कि वहां बहुत सारे आवश्यक कोड हैं। – anon58192932

+1

@advocate [कितना बड़ा बड़ा है?] (Http://en.wikipedia.org/wiki/Buffer_overflow) मैं एक उचित आकार के बफर से शुरू करता हूं और इसे आवश्यकतानुसार विस्तारित करता रहता हूं। वास्तव में बफर के लिए एक और जांच होनी चाहिए ताकि आपके कंप्यूटर को स्मृति से बाहर निकलने से रोका जा सके, यदि कोई स्ट्रीम स्ट्रीम नहीं कर रहा है, लेकिन यह एक साधारण सीखने का अभ्यास था। –

4

याद रखें: fgetc(), getc(), getchar() सभी एक पूर्णांक लौटाते हैं, न कि चार। पूर्णांक ईओएफ या वैध चरित्र हो सकता है - लेकिन यह चार प्रकार द्वारा समर्थित श्रेणी से एक और मूल्य देता है।

आप fgrep 'कमांड के लिए एक किराए लिख रहे हैं: - fgets का उपयोग कर()

fgrep -f strings.txt text_file.txt > out.txt 

के बजाय पढ़ने वर्ण, आप लाइनों पढ़ने की जरूरत करने जा रहे हैं। (भूल जाओ कि हो जाता है() फ़ंक्शन मौजूद है!)

मैंने आपके कोड को इंडेंट किया और वापसी 0 डाला; आपके लिए अंत में (हालांकि सी 99 एक अंतर्निहित 'वापसी 0;' है यदि आप मुख्य() के अंत से गिर जाते हैं)। हालांकि, सी 99 भी प्रत्येक फंक्शन के लिए एक स्पष्ट रिटर्न प्रकार की मांग करता है - और मैंने आपके लिए 'int' 'int main()' जोड़ा है (लेकिन आप अंत में 0 लौटने के लिए C99-compliant बहाना का उपयोग नहीं कर सकते हैं)। त्रुटि संदेश मानक आउटपुट के बजाय मानक त्रुटि पर लिखा जाना चाहिए।

आप शायद तार की सूची के लिए गतिशील आवंटन का उपयोग करना होगा। एक साधारण दिमागी खोज इनपुट की प्रत्येक पंक्ति में प्रत्येक आवश्यक स्ट्रिंग के लिए 'स्ट्रस्ट्र()' खोज को लागू करेगी (एक मैच मिलने के बाद लूप को तोड़ना सुनिश्चित करें ताकि एकाधिक मिलान होने पर लाइन दोहराया न जाए एक पंक्ति पर)।

एक और परिष्कृत खोज प्रीकंप्यूट करेगी कि कौन से पात्रों को अनदेखा किया जा सकता है ताकि आप समांतर में सभी तारों को खोज सकें, लूप-इन-ए-लूप से टेक्स्ट को तेज़ी से छोड़ दें। इस तरह के बोयर-मूर या नुथ-मॉरिस-प्रैट के रूप में एक खोज एल्गोरिथ्म के एक संशोधन हो सकता है ( कहा: या राबिन-कार्प जो कई तार के लिए समानांतर खोज के लिए डिज़ाइन किया गया है)। क्योंकि यह कैसे अंतर्निहित फाइल सिस्टम काम करता है

+0

व्यक्तिगत रूप से मैं पात्रों को बफर करने के लिए एक फ़ंक्शन लिखना पसंद करता हूं ... अकेले fgets का उपयोग करके आप लाइन की लंबाई पर मनमाने ढंग से सीमाएं देते हैं। – asveikau

+0

@asveikau: मुझे अंतर नहीं दिख रहा है? Fgets का उपयोग करते समय हम बफर प्रदान करते हैं, हम इसे किसी भी आकार को सेट कर सकते हैं। और यदि strings.txt में रेखाएं बफर से अधिक हैं तो हम किसी भी तरह से परेशानी में हैं ... क्या आपका मतलब है कि हमें fgets का उपयोग करते समय भी बफर ओवरफ़्लो केस प्रबंधित करना चाहिए? हाँ वास्तव में और यह एक untyped बफर के साथ कम स्पष्ट है। – kriss

+0

fgets() दिए गए बफर लंबाई तक पढ़ता है; यदि इसे अंतरिक्ष से बाहर होने तक एक नई लाइन का सामना नहीं हुआ है, तो यह बंद हो जाता है और लौटाता है। इसलिए, यदि अंतिम चरित्र नई लाइन नहीं है और बफर भरा हुआ है, तो आप अतिरिक्त वर्णों को रखने के लिए कुछ और स्थान (पुनः आवंटित?) पा सकते हैं, फिर से fgets() को कॉल करें (सावधानी से - यह कहां समाप्त हो गया है, केवल इसे बता रहा है अतिरिक्त जगह) और लाइन के अधिक प्राप्त करें। तो हां, आप गतिशील रूप से आवंटित बफर में डेटा प्राप्त करने के लिए अपना स्वयं का पाठक लिख सकते हैं - या बफर को संभालने के दौरान पढ़ने के लिए fgets() का उपयोग करें। –

2

ब्लॉक से पढ़ना, हमेशा बेहतर है।

इसलिए सिर्फ ब्लॉकों द्वारा पढ़ा, तो देखें कि आपके शब्दों के किसी भी बफर में दिखाई देते हैं, फिर एक और बफर पूरा पढ़ें। यदि खोज शब्द बफर सीमा पर हैं तो आपको लापता पहचान से बचने के लिए नए बफर के पिछले कुछ पात्रों को दोबारा शुरू करने के लिए सावधान रहना होगा।

यदि यह मामूली एल्गोरिदम पर्याप्त नहीं है (आपके मामले में यह शायद है) एक बफर सीएफ Rabin-Karp में एक साथ कई सबस्ट्रिंग खोजने के लिए बहुत अधिक परिष्कृत एल्गोरिदम है।

+0

जब आप fgetc() का उपयोग करते हैं, तो मैं निश्चित रूप से कुछ निश्चित stdio ब्लॉक और बफर वर्णों द्वारा पढ़ा जाएगा ... – asveikau

+0

सच है, लेकिन fgetc को कॉल करना इसकी लागत है और यदि आप स्ट्रिंग (या कई तारों) के साथ इनपुट की तुलना करना चाहते हैं आपको इसे कहीं कॉपी करना होगा। एक पूर्ण बफर पढ़ने और इसके साथ काम करने की तुलना में इसकी बहुत अधिक लागत है। जोनाथन प्रस्ताव के रूप में एक पूर्ण पंक्ति पढ़ना भी एक पूर्ण बफर पढ़ने का एक अच्छा विकल्प है यदि आप स्वयं को बफर पढ़ने के लिए गोरियों का विवरण प्रबंधित नहीं करना चाहते हैं। – kriss

2
cat strings.txt |while read x; do grep "$x" text_file.txt; done 
+1

आपका मतलब था 'fgrep -f strings.txt text_file.txt> out.txt'? –

+0

हां, हां, 'fgrep -f strings.txt text_file.txt'। मुझे लगता है कि अधिक एक्सपोजर का मतलब अधिक विकल्प है। –

+0

धन्यवाद। ऐसा करने के लिए एक सी प्रोग्राम लिखना समय की पूरी बर्बादी है। –

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