एक फ़ाइल पार्स करने का सबसे अच्छा तरीका है


9

मैं कुछ प्रसिद्ध फ़ाइल स्वरूपों के लिए एक पार्सर बनाने के लिए एक बेहतर समाधान खोजने की कोशिश कर रहा हूँ जैसे: EDIFACT और TRADOMOMS

यदि आप इन मानकों से परिचित नहीं हैं तो विकिपीडिया से इस उदाहरण को देखें:

उत्पाद उपलब्धता अनुरोध का उत्तर देने के लिए उपयोग किए गए EDIFACT संदेश के उदाहरण के लिए नीचे देखें: -

UNA:+.? '
UNB+IATB:1+6XPPC+LHPPC+940101:0950+1'
UNH+1+PAORES:93:1:IA'
MSG+1:45'
IFT+3+XYZCOMPANY AVAILABILITY'
ERC+A7V:1:AMD'
IFT+3+NO MORE FLIGHTS'
ODI'
TVL+240493:1000::1220+FRA+JFK+DL+400+C'
PDI++C:3+Y::3+F::1'
APD+714C:0:::6++++++6X'
TVL+240493:1740::2030+JFK+MIA+DL+081+C'
PDI++C:4'
APD+EM2:0:130::6+++++++DA'
UNT+13+1'
UNZ+1+1'

UNA सेगमेंट वैकल्पिक है। यदि मौजूद है, तो यह उन विशेष वर्णों को निर्दिष्ट करता है जिनका उपयोग शेष संदेश की व्याख्या करने के लिए किया जाना है। इस क्रम में UNA के बाद छह वर्ण हैं:

  • घटक डेटा तत्व विभाजक (इस नमूने में)
  • डेटा तत्व विभाजक (इस नमूने में)
  • दशमलव अधिसूचना (इस नमूने में)
  • रिलीज चरित्र (इस नमूने में)
  • आरक्षित होना चाहिए, एक स्थान होना चाहिए
  • खंड टर्मिनेटर ('इस नमूने में)

जैसा कि आप देख सकते हैं कि यह केवल कुछ विशेष रूप से पार्स किए जाने के इंतजार में प्रारूपित डेटा है (बहुत कुछ XML फ़ाइलों की तरह )।

अब मेरा सिस्टम PHP पर बनाया गया है और मैं प्रत्येक सेगमेंट के लिए नियमित एक्सप्रेशन का उपयोग करके पार्सर बनाने में सक्षम था, लेकिन समस्या यह नहीं है कि हर कोई मानक को पूरी तरह से लागू करता है।

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

आप नियमित अभिव्यक्ति की दुःस्वप्न की कल्पना कर सकते हैं जो मैं अभी कर रहा हूं। इसके अलावा, प्रत्येक आपूर्तिकर्ता को नियमित अभिव्यक्तियों के लिए कई संशोधनों की आवश्यकता होती है जो मैं प्रत्येक आपूर्तिकर्ता के लिए एक पार्सर बनाने के लिए करता हूं।


प्रशन:

1- क्या यह पार्सिंग फ़ाइलों (नियमित अभिव्यक्ति का उपयोग करके) के लिए सबसे अच्छा अभ्यास है?

2- क्या पार्सिंग फ़ाइलों के लिए एक बेहतर समाधान है (हो सकता है कि वहाँ तैयार समाधान हो)? क्या यह दिखाने में सक्षम होगा कि क्या खंड गायब है या यदि फ़ाइल दूषित है?

3- अगर मुझे अपने पार्सर का निर्माण करना है, तो मुझे किस डिज़ाइन पैटर्न या कार्यप्रणाली का उपयोग करना चाहिए?

टिप्पणियाँ:

मैंने याक और ANTLR के बारे में कहीं पढ़ा है, लेकिन मुझे नहीं पता कि वे मेरी ज़रूरतों से मेल खाते हैं या नहीं!


इस EDIFACT व्याकरण, पार्सर्स और लाइब्रेरीज़ (जावा) को देखने के बाद मुझे आश्चर्य होता है कि क्या कोई लेसर / पार्सर काम करेगा। अगर यह मैं होता तो मैं पहले पार्सर कॉम्बीनेटर की कोशिश करता। :)
गाय कोडर

जवाबों:


18

आपको जो चाहिए वह एक सही पार्सर है। नियमित अभिव्यक्ति लेक्सिंग को संभालती है, पार्सिंग को नहीं। यही है, वे आपके इनपुट स्ट्रीम के भीतर टोकन की पहचान करते हैं। पार्सिंग टोकन का संदर्भ है, IE जो कहाँ और किस क्रम में जाता है।

क्लासिक पार्सिंग टूल याक / बाइसन है । क्लासिक लेक्सर लेक्स / फ्लेक्स है । चूंकि php C कोड को एकीकृत करने की अनुमति देता है , आप अपने पार्सर के निर्माण के लिए फ्लेक्स और बाइसन का उपयोग कर सकते हैं, php को इनपुट फाइल / स्ट्रीम पर कॉल कर सकते हैं, और फिर अपने परिणाम प्राप्त कर सकते हैं।

यह तेजी से धधक रहा होगा , और जब तक आप उपकरण को समझ नहीं लेते , तब तक काम करना आसान होगा । मेरा सुझाव है कि लेक्स और याक 2 डी एड पढ़ना ओ'रेली से। उदाहरण के लिए, मैंने एक फ्लेफ़ और बाइसन प्रोजेक्ट को गितुब पर स्थापित किया है , मेकफाइल के साथ। यदि आवश्यक हो तो यह खिड़कियों के लिए पार करने योग्य है।

यह है जटिल है, लेकिन जैसा कि आप में पता चला, तुमने क्या किया की जरूरत है जटिल है। "सामान" का एक बड़ा सौदा है जो ठीक से काम करने वाले पार्सर के लिए किया जाना चाहिए, और यांत्रिक बिट्स के साथ फ्लेक्स और बाइसन सौदा। अन्यथा, आप अपने आप को असेंबली के रूप में एक ही अमूर्त परत पर कोड लिखने की असम्भव स्थिति में पाते हैं।


1
+1 महान जवाब, विशेष रूप से यह देखते हुए कि यह एक नमूना पार्सर के साथ आता है।
कालेब

@ कॉलेब धन्यवाद, मैं फ्लेक्स / बायसन के साथ बहुत काम करता हूं, लेकिन बहुत कम सभ्य (पढ़ें: जटिल) उदाहरण हैं। यह अब तक का सबसे अच्छा पार्सर नहीं है, क्योंकि कई टिप्पणियां नहीं हैं, इसलिए अपडेट में भेजने के लिए स्वतंत्र महसूस करें।
स्पेंसर रथबुन

@SpencerRathbun आपके विस्तृत उत्तर और उदाहरण के लिए बहुत बहुत धन्यवाद। मुझे इस बात का कोई ज्ञान नहीं है कि आपके द्वारा बताई गई शब्दावली (yacc / bison, lex / flex, ... आदि) में से किसी के बारे में ऐसा क्या है, जैसा कि मेरा अनुभव मुख्य रूप से वेब विकास के बारे में है। क्या "लेक्स और याक 2 एड" मेरे लिए सब कुछ समझने और एक अच्छा पार्सर बनाने के लिए पर्याप्त है? या क्या अन्य विषय और सामग्री हैं जिन्हें मुझे पहले कवर करना चाहिए?
सांगो

@songo पुस्तक सभी प्रासंगिक विवरणों को कवर करती है और यह काफी कम है, जो कि ~ 300 मिड साइज पेजों पर आधारित है। यह c, या भाषा डिज़ाइन का उपयोग करके कवर नहीं करता है । सौभाग्य से, बहुत सारे c संदर्भ उपलब्ध हैं, जैसे K & R C C प्रोग्रामिंग लैंग्वेज और आपको कोई भाषा डिज़ाइन करने की आवश्यकता नहीं है, बस आपके द्वारा निर्दिष्ट मानकों का पालन करें। कृपया ध्यान दें कि कवर को पढ़ने के लिए कवर की सिफारिश की गई है, क्योंकि लेखक एक बार कुछ का उल्लेख करेंगे, और मान लें कि यदि आपको इसकी आवश्यकता है तो आप वापस जाएंगे और फिर से पढ़ना चाहेंगे। इस तरह आप कुछ भी याद नहीं करते हैं।
स्पेंसर रथबून

मुझे नहीं लगता कि एक मानक लेक्सर गतिशील विभाजक को संभाल सकता है, जिसे यूएनए लाइन निर्दिष्ट कर सकती है। तो कम से कम आपको 5 विभाजकों के लिए रनटाइम-अनुकूलन योग्य वर्णों के साथ एक लेक्सर की आवश्यकता होगी।
केविन

3

ouch .. 'सच' पार्सर? राज्य की मशीनें ??

क्षमा करें, लेकिन मैं अपना रोजगार शुरू करने के बाद से शैक्षणिक से हैकर में परिवर्तित हो गया हूं .. इसलिए मैं कहूंगा कि आसान तरीके हैं .. हालांकि अकादमिक रूप से 'परिष्कृत' नहीं हो सकता है :)

मैं एक वैकल्पिक दृष्टिकोण की पेशकश करने की कोशिश करूंगा जो कुछ के साथ सहमत हो सकता है या नहीं हो सकता है लेकिन यह काम के माहौल में बहुत व्यावहारिक हो सकता है।

मैं;

loop every line
   X = pop the first 3 letters of line
   Y = rest of line
   case X = 'UNA':
       class init (Y)

वहाँ से मैं डेटा प्रकारों के लिए कक्षाओं का उपयोग करूँगा। विभाजन घटक और तत्व विभाजक और लौटे सरणियों पर पुनरावृति।

मेरे लिए, यह कोड पुनः उपयोग, OO, कम सामंजस्य और अत्यधिक मॉड्यूलर है .. और डिबग और प्रोग्राम के लिए आसान है। सरल बेहतर है।

एक फाइल को पार्स करने के लिए आपको राज्य मशीनों या पूरी तरह से जटिल किसी भी चीज की आवश्यकता नहीं है .. राज्य मशीनें पार्स कोड के अनुकूल हैं, आपको इस बात पर आश्चर्य होगा कि एक ओओ संदर्भ में उपयोग किए जाने पर उपरोक्त pseduo कोड कितना शक्तिशाली हो सकता है।

ps। मैं पहले बहुत समान फ़ाइलों के साथ काम किया है :)


अधिक छद्म कोड यहाँ पोस्ट किया गया:

कक्षा

UNA:

init(Y):
 remove ' from end
 components = Y.split(':') 
 for c in components
     .. etc..

 getComponents():
   logic..
   return

 getSomethingElse():
   logic..
   return

class UNZ:
   ...

Parser(lines):

Msg = new obj;

for line in lines
   X = pop the first 3 letters of line
   Y = rest of line
   case X = 'UNA':
      Msg.add(UNA(Y))

msg.isOK = true
return Msg

तुम तो इस तरह का उपयोग कर सकते हैं ..

msg = Main(File.getLines());
// could put in error checking
// if msg.isOK:
msg.UNA.getSomethingElse();

और कहें कि आपके पास एक से अधिक खंड हैं .. उन्हें जोड़ने के लिए एक कतार का उपयोग करें और अपनी आवश्यकता के अनुसार पहला, दूसरा आदि प्राप्त करें। आप वास्तव में केवल एक ओब्स में संदेश का प्रतिनिधित्व कर रहे हैं और डेटा को कॉल करने के लिए ऑब्जेक्ट तरीके दे रहे हैं। आप कस्टम विधि बनाकर इसका लाभ उठा सकते हैं .. वंशानुक्रम के लिए .. अच्छी तरह से यह एक अलग सवाल है और मुझे लगता है कि आप इसे आसानी से लागू कर सकते हैं यदि आप इसे समझते हैं


3
मैंने ऐसा पहले किया है, और पाया कि यह एक या दो मामलों से परे किसी भी चीज के लिए अपर्याप्त है recognize X token and do Y। कोई संदर्भ नहीं है, आपके पास एक से अधिक राज्य नहीं हो सकते हैं, पिछले मामलों की एक छोटी संख्या में कोड को धुंधला कर दिया जाता है, और त्रुटि से निपटने में मुश्किल होती है। मुझे लगता है कि मुझे लगभग सभी मामलों में वास्तविक दुनिया में इन विशेषताओं की आवश्यकता है। जटिलता के बढ़ने के साथ ही इसमें गलतियाँ हो जाती हैं। सबसे कठिन हिस्सा एक कंकाल स्थापित कर रहा है, और यह सीख रहा है कि उपकरण कैसे संचालित होता है। अतीत हो जाओ और यह बस के रूप में तेजी से कुछ कोड़ा है।
स्पेंसर रथबुन

यह एक संदेश है, आपको किन राज्यों की आवश्यकता है? ऐसा लगता है कि ऐसा संदेश, जो कंपोजिट और सेगमेंट की संरचना में व्यवस्थित है, इस OO दृष्टिकोण को पूरी तरह से फिट करेगा। त्रुटि से निपटने के प्रति वर्ग किया जाता है और ठीक से किया जाता है आप एक पार्सर का निर्माण कर सकते हैं जो बहुत कुशल और एक्स्टेंसिबल है। इस तरह के संदेश विशेष रूप से कई विक्रेताओं को एक ही प्रारूप के विभिन्न स्वाद भेजने के लिए खुद को कक्षाओं और कार्यों के लिए उधार देते हैं। एक उदाहरण यूएनए वर्ग में एक फ़ंक्शन होगा जो एक विशिष्ट विक्रेता के लिए एक विशेष मूल्य लौटाता है।
रॉस

@Ross तो बुनियादी तौर पर आप एक होगा "ऊना वर्ग" खंड के लिए "ऊना" (वहाँ प्रत्येक विक्रेता के लिए एक पार्स विधि हो जाएगा और इसके अंदर parseUNAsegemntForVendor1(), parseUNAsegemntForVendor2(), parseUNAsegemntForVendor3(), ... आदि), है ना?
सांगो

2
@ पोस्ट संदेश के अनुभाग हैं, जो पार्सिंग के दौरान विभिन्न बिंदुओं पर मान्य हैं। मैं जिन राज्यों के बारे में बात कर रहा था। OO डिजाइन चतुर है, और मैं यह नहीं कहूंगा कि यह काम नहीं करेगा । मैं फ्लेक्स और बाइसन को धक्का देता हूं क्योंकि कार्यात्मक प्रोग्रामिंग अवधारणाओं की तरह, वे अन्य उपकरणों की तुलना में बेहतर फिट होते हैं, लेकिन ज्यादातर लोग मानते हैं कि वे सीखने को परेशान करने के लिए बहुत जटिल हैं।
स्पेंसर रथबुन

@Songo .. नहीं, आप विक्रेता के स्वतंत्र रूप से पार्स करेंगे (जब तक कि आप नया नहीं है)। पार्स कक्षा के INIT में होगा। आप अपने संदेश को संदेश के निर्माण के लिए उपयोग किए गए समान नियमों के आधार पर एक डेटा ऑब्जेक्ट में बदल देते हैं। यदि आपको संदेश से कुछ हासिल करने की आवश्यकता है, लेकिन यह आपके विक्रेताओं में अलग तरह से दर्शाया गया है, तो आपके पास अलग-अलग फ़ंक्शन होंगे .. लेकिन ऐसा क्यों है? एक आधार वर्ग का उपयोग करें और प्रत्येक विक्रेता के लिए एक अलग वर्ग है, केवल आवश्यक होने पर ओवरराइड करना, बहुत आसान है। विरासत का लाभ उठाएं।
रॉस

1

क्या आपने "PHP EDIFACT" के लिए गुग्लिंग करने की कोशिश की है? यह उन पहले परिणामों में से एक है जो पॉप अप किया गया है: http://code.google.com/p/edieasy/

हालांकि यह आपके उपयोग के मामले के लिए पर्याप्त नहीं हो सकता है, आप इससे कुछ विचार प्राप्त करने में सक्षम हो सकते हैं। मुझे लूप और शर्तों के लिए इसके कई नेस्ट वाले कोड पसंद नहीं हैं, लेकिन यह एक शुरुआत हो सकती है।


1
मैंने कई परियोजनाओं की जाँच की, लेकिन समस्या मुख्यतः मानक का उपयोग करने वाले विक्रेताओं के विभिन्न कार्यान्वयन में थी। मैं एक विक्रेता को मुझे एक निश्चित खंड भेजने के लिए मजबूर कर सकता हूं, लेकिन मैं इसे दूसरे विक्रेता के लिए वैकल्पिक मान सकता हूं। यही कारण है कि मैं शायद वैसे भी अपने खुद के अनुकूलित पार्सर बनाने की जरूरत है।
सोंगो

1

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

सामान्य अवधारणा यह है कि आप छोटे, आसान परिभाषित पार्सर, आमतौर पर टोकनधारकों के एक सेट से शुरू करते हैं। जैसे आपके द्वारा बताए गए 6 डेटा तत्वों में से प्रत्येक के लिए एक पार्सर फ़ंक्शन होगा। फिर आप बड़े तत्वों को खींचने वाले बड़े पार्सर बनाने के लिए कॉम्बिनेटर (फ़ंक्शंस जो फ़ंक्शंस को मिलाते हैं) का उपयोग करते हैं। वैकल्पिक सेगमेंट की तरह optionalसेगमेंट पार्सर पर चलने वाला कॉम्बिनेटर होगा ।

यह निश्चित नहीं है कि यह PHP में कितनी अच्छी तरह काम करता है, लेकिन यह एक पार्सर लिखने का एक मजेदार तरीका है और मुझे अन्य भाषाओं में उनका उपयोग करने में बहुत मज़ा आता है।


0

बजाय regexes के साथ fiddling अपने राज्य मशीन बनाते हैं

यह गैर-तुच्छ परिस्थितियों में अधिक पठनीय होगा (और बेहतर टिप्पणी करने में सक्षम होगा) डीबग करना आसान होगा जो ब्लैक बॉक्स रेगेक्स है


5
एक त्वरित टिप्पणी, यह वही है जो हुड के नीचे फ्लेक्स और बाइसन करता है। केवल वे इसे सही करते हैं
स्पेंसर रथबुन

0

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.