TCL और कुछ संख्या प्रणालियों पर IPv4 पतों की सूची बनाना

ऐसा नहीं है कि बहुत पहले उपकरणों के विन्यास को अद्यतन करने वाले द्रव्यमान की समस्या को हल करना आवश्यक था। यदि आपके पास सेवा में समान कार्य करने वाले एक से अधिक उपकरण हैं, तो एक मानक प्रणाली प्रशासन कार्य। समाधान के लिए सार्वभौमिक उत्पाद हैं, उदाहरण के लिए, उपलब्ध redmine.nocproject.org से , साथ ही साथ कई स्क्रिप्ट व्यापक रूप से विषयगत मंचों और पोर्टलों पर प्रतिनिधित्व करते हैं। बस इस मामले के लिए, आपकी खुद की लिखी गई स्क्रिप्ट हाथ में होनी चाहिए थी, लेकिन यह नहीं निकला, इसलिए यह देखते हुए कि युद्धाभ्यास का समय था, स्क्रिप्ट को फिर से लिखा गया, निष्पादित किया गया और इसे एक शेल्फ पर रखा गया ताकि यह फिर से खो जाए।
लिखने के लिए, हमने टीसीएल पर ऐड-ऑन। सोर्सफोर्जगे , एक ऐड-ऑन का उपयोग किया, जो आपको विशेष रूप से टेलनेट में विभिन्न इंटरैक्टिव कंसोल उपयोगिताओं की प्रतिक्रियाओं की प्रक्रिया और प्रतिक्रिया करने की अनुमति देता है। यह देखते हुए कि टीसीएल को पहले नहीं लिखा गया था, कोड को फिर से चाहिए। स्क्रिप्ट का महत्वपूर्ण क्षण प्रसंस्करण के लिए IPv4 पतों की सूची का जनरेटर है, एक सावधानीपूर्वक मूल्यांकन के बाद, कार्यक्रम का यह टुकड़ा महत्वपूर्ण रूप से सक्षम था, मेरी राय में, अनुकूलन, कम से कम लाइनों की संख्या को एक तिहाई से कम करें और दर्द रहित रूप से नई कार्यक्षमता जोड़ें। इसके अलावा, इन सभी संक्षिप्तीकरणों का बंधन की बारीकियों से बहुत कम संबंध था, लेकिन समग्र रूप से एल्गोरिथ्म के निर्माण के लिए संबंधित मूलभूत दृष्टिकोण।
मैंने इस कोड को एक अलग उपयोगिता के रूप में आवंटित किया है, जिसे मैं बाद में पाठ पर बहुत विस्तार से विश्लेषण करने की कोशिश करूंगा - यह "पहले" कैसे था और "बाद" क्या बन गया, और क्यों "के बाद" के रूप में सही लिखना संभव नहीं था। मैं अभी भी इसके बारे में सब कुछ पसंद नहीं करता हूं: दोनों एल्गोरिथम समस्याएं और टीसीएल समस्याएं, उदाहरण के लिए, सरणियों के बजाय सूचियों का उपयोग करना (जो तेज है; सुरक्षित, वैचारिक रूप से अधिक सटीक?), सभी संदेह पाठ में भी मौजूद हैं, रचनात्मक टिप्पणियों की उम्मीद के साथ।
उपयोगिता का तर्क (cipl.tl) निम्नानुसार है - कमांड लाइन पर हम दो पैरामीटर सेट करते हैं: IPv4 पता जिससे हम अपनी सूची बनाना शुरू करेंगे और IPv4 पता जिसके साथ सूची समाप्त होती है या एक संख्या बताती है कि सूची में कितने होने चाहिए। निर्माण का क्रम निचले पते (पहले पैरामीटर) से बड़ा होता है। यदि दूसरा पैरामीटर छोड़ा जाता है, तो केवल प्रारंभ IPv4 पते वाली सूची प्रदर्शित की जाती है:
 > cipl.tl 192.0.2.1 1
 192.0.2.1
 192.0.2.2
 > cipl.tl 192.0.2.1 192.0.2.2
 192.0.2.1
 192.0.2.2
 > cipl.tl 192.0.2.1
 192.0.2.1

विंडोज के लिए, स्क्रिप्ट को टैक्श इंटरप्रेटर के साथ लॉन्च किया गया है, वास्तव में यह * निक्स में भी किया जा सकता है
 > tclsh cipl.tl 192.0.2.1
 192.0.2.1

इसके अलावा मैं कोड को उद्धृत करूंगा, इसे लाइन नंबर और संस्करण प्रदान करूंगा, और फिर उस पर टिप्पणी करूंगा। परिणामी संस्करण, आप विषय के अंत में लिंक उठा सकते हैं।

Ver। 1, नंबर 1-12
#!/usr/bin/tclsh8.5 set exip {^(2(5[0-5]|[0-4]\d)|1\d{2}|[1-9]\d{0,1})(\.(2(5[0-5]|[0-4]\d)|1\d{2}|[1-9]\d|\d)){3}$} set exdg {^(0?|([1-9]\d{0,5}))$} if {$argc == 0 || $argc > 2} then { puts "cipl.tl -   IP    " puts ": cipl.tl <start IP> \[<count>|<finish IP>\]" puts ": <start IP> - IPv4     <finish IP>" puts "\t <finish IP> - IPv4 " puts "\t <count> -   0  999999" } else { 

पहली पंक्ति से पता चलता है कि हमें किस दुभाषिया का उपयोग करने की आवश्यकता है, यह लिनक्स के लिए रेखा है। सामान्य तौर पर, आपको tclsh के लिए पूर्ण पथ निर्दिष्ट करने की आवश्यकता है, उदाहरण के लिए, FreeBSD के लिए यह रेखा इस तरह दिखाई देगी:
 #!/usr/local/bin/tclsh8.5 

अगला, हम एक्सिप और एक्सडग चर निर्धारित करते हैं , जो नियमित अभिव्यक्ति हैं जो हम कार्यक्रम में आगे उपयोग करेंगे। हमें यह सत्यापित करने के लिए पहला चर चाहिए कि IPv4 पता सही दर्ज किया गया है। दशमलव के रूप में लिखे गए सही पते १०.०.०५ से २५५.२५.२५.२५.२५ तक इस नियमित अभिव्यक्ति के अंतर्गत आते हैं, अर्थात् यह फॉर्म १ ९ २.०.०२.०१ का पता निर्धारित करने के लिए काम नहीं करेगा। दूसरा चर संख्या को निर्धारित करता है, प्रमुख शून्य के बिना - सूची की वैध सीमाएं 0 से 999999 तक हैं, एक खाली स्ट्रिंग भी सच है। 999999 से ऊपर का प्रतिबंध, मेरी राय में, उचित था और, इसके अलावा, मैंने 32 वें नंबर की डिग्री में 2 नंबर के अनुरूप एक नियमित अभिव्यक्ति की तलाश में समय बर्बाद नहीं किया। ये नियमित अभिव्यक्ति तुरंत प्रकट नहीं हुईं, लेकिन समाधान की जरूरतों के आधार पर जोड़ दी गईं, जो बताती हैं कि वे क्यों इस तरह, लेकिन यह थोड़ा आगे देखा जाएगा।
अगला, यदि स्थिति की जांच की जाती है - कमांड लाइन से पारित मापदंडों की संख्या, यदि 0 या 2 से अधिक है, तो एक छोटी सी सहायता प्रदर्शित की जाती है। इस बिंदु पर, आपको कुछ भी आउटपुट करने की आवश्यकता नहीं है, लेकिन पहले दो मापदंडों को वांछित के रूप में लें, जिससे त्रुटि के मामले में आउटपुट को अव्यवस्थित किए बिना उपयोगिता के बैच ऑपरेशन पर अधिक ध्यान केंद्रित किया जा सके।
अंतिम पंक्ति एक और ब्लॉक खोलती है जिसमें मुख्य प्रसंस्करण होता है।

Ver। 1, नंबर 12-17
 } else { set startip [lindex $argv 0] set countip [lindex $argv 1] set getcountip $countip if {[regexp $exip $startip]} then { set octsip [split $startip {.}] 

इस भाग में, हम सबसे पहले इनपुट वेरिएबल्स में प्राप्त होने वाले मापदंडों को सहेजते हैं - पहला पैरामीटर, काउंटरिप - दूसरा पैरामीटर, अगर कोई दूसरा पैरामीटर नहीं है, तो लिंडेक्स हमारे लिए एक खाली स्ट्रिंग लौटाएगा। और अतिरिक्त वैरिएबल गेटकाउंट में दूसरे पैरामीटर को भी सहेजें।
इसके बाद, हम जाँचते हैं कि पहला पैरामीटर regexp और पूर्व निर्धारित चर के साथ एक्सिप चर का उपयोग करके सही IP पते से मेल खाता है। इस स्थिति में, यह महत्वपूर्ण है कि IPv4 पता पूरी तरह से संगत है जो हम उम्मीद करते हैं, अगली पंक्ति के बाद से हम विभाजन के साथ ऑक्टस सूची बनाते हैं, डॉट चरित्र एक विभाजक के रूप में कार्य करता है। परिणामी सूची में केवल शून्य अंकों में 0 से 255 तक प्रमुख शून्य के बिना सही जगह पर होना चाहिए ताकि आगे अतिरिक्त जांच के बिना उनके साथ काम किया जा सके। अग्रणी शून्य यहां एक भूमिका निभाते हैं, जैसे कि, उदाहरण के लिए, नंबर 011, जब प्रतिस्थापित किया जाता है, तो इसे एक ऑक्टल नंबर माना जाएगा, अर्थात यह दशमलव संख्या प्रणाली में 9 के बराबर होगा।
यह इस तथ्य पर ध्यान देने योग्य है कि एक खोज इंजन में एक क्वेरी अक्सर नियमित अभिव्यक्ति की ओर ले जाती है जो इन सभी स्थितियों की जांच नहीं करती है, अक्सर यह एक समूह में 3 अंकों के 4 समूहों के लिए एक चेक होता है। उदाहरण के लिए, habrahabr.ru/blogs/webdev/123845 से अभिव्यक्ति - 000.100.1.010 के निर्माण की अनुमति देता है, जो निश्चित रूप से आईपी पता है, लेकिन स्पष्ट रूप से इसके अष्टाधारी या दशमलव रूप का निर्धारण नहीं करता है, यह अनिश्चितता का परिचय देता है और आगे सत्यापन की आवश्यकता है।

Ver। 1, No.104
 if {[regexp $exip $countip]} then { set octfip [split $countip {.}] set octsub {0} set countip {0} for {set i 3} {$i>=0} {incr i -1} { if {[set octsub [expr [lindex $octfip $i] - [lindex $octsip $i]]] < 0} then { if {$i > 0} then { set si [expr $i - 1] set octfip [lreplace $octfip $si $si [expr [lindex $octfip $si] - 1]] set octsub [expr 256 + $octsub] } else { break } } set ni [expr 3 - $i] set countip [expr $countip + ($octsub * (1 << ($ni * 8)))] } } 

यहां हम जांचते हैं कि दूसरा पैरामीटर एक मान्य IPv4 पता है और यदि ऐसा है, तो हम इस पते और पहले पैरामीटर में निर्दिष्ट एक के बीच के अंतर की गणना करने की कोशिश करते हैं, अर्थात् , इस ब्लॉक के आउटपुट पर, काउंटर चर में सूची लंबाई का सही मान होना चाहिए। यदि चेक अपस्ट्रीम चेक (लाइन 16) में स्थित है, तो यदि पिछला चेक फेल हो गया है (पहला पैरामीटर IPv4 एड्रेस नहीं है) तो प्रोग्राम इस सेक्शन तक नहीं पहुंचेगा।
इस सबटैक् स का समाधान (IPv4 पतों को घटाते हुए) किया जाता है, जैसे कि हम एक कॉलम में दो संख्याओं को घटाते हैं:
  192.168.3।  1
 -192.168.2।  10
 = 0. 0.0.247

बेशक, ये संख्या दशमलव नहीं है, लेकिन 256 के आधार पर है। अर्थात, जब हम पिछले अंक से मूल्य लेते हैं, तो हमें ओकटास के हेक्साडेसिमल प्रतिनिधित्व में 10 नहीं, बल्कि 256 (0x100) जोड़ना चाहिए, यह अधिक स्पष्ट रूप से दिखता है:
  0xC0.0xA8.0x03.0x01
 -0xC0.0xA8.0x02.0x0A
 ---------------------- (हम ऋण लेते हैं, वरिष्ठ स्तर से इकाई को हटाते हैं)
 = 0xC0.0xA8.0x03.0x01
          -.0x01
 ---------------------- (हम ऋण जारी रखते हैं, हम संख्या प्रणाली के आधार के मूल्य द्वारा परिणाम को समायोजित करते हैं)
 -0xC0.0xA8.0x02.0x00A
               + .0x100
 ---------------------- (परिणाम एक ऐसा ऑपरेशन है)
 = 0xC0.0xA8.0x02.0x101
 -0xC0.0xA8.0x02.0x00A
 = 0x00.0x00.0x00.0x0F7

इसे लागू करने के लिए, हम, साथ ही साथ पहले पैरामीटर के साथ, otcfip सूची बनाएं, फिर ऑक्टसब चर बनाएं, जिसमें ऑक्टेट्स के बीच अंतर होगा और काउंटरिप को शून्य किया जाएगा जो पता सूची के आकार को संग्रहीत करेगा, और आईपीवी 4 पता नहीं, जब हमने दर्ज किया था। कोड का यह ब्लॉक।
हम 3 से 0. तक उल्टे क्रम में वेरिएबल i के साथ लूप के लिए व्यवस्थित करते हैं। इस लूप में, हमें IPv4 पते के सभी ऑक्टेट से गुजरना चाहिए, जो कि सबसे निचले से शुरू होता है, यानी ऑक्टसिप और ऑक्टाफ़िप सूची के सभी तत्व अंतिम तत्व से शुरू होते हैं।
हम वर्तमान ओकटेट्स ऑक्टीफ-ऑक्टिल के बीच अंतर की गणना करते हैं और इसे ऑक्टस में बचाते हैं । मैं वास्तव में यहां सरणियों का उपयोग करना चाहता था, क्योंकि लिंडेक्स के साथ निर्माण बहुत बोझिल है, लेकिन मैंने सूची से एक सरणी बनाने के लिए एक आसान तरीका नहीं देखा (टीसीएल में यह केवल साहचर्य है), इसलिए केवल सूचियां हर जगह हैं। परिकलित अंतर को 0 से कम की स्थिति के लिए तुरंत जांचा जाता है, अर्थात, क्या हमें उच्च ऑक्टेट से ऋण लेने की आवश्यकता है या नहीं?
यदि आपको ऋण लेने की आवश्यकता है और यह सबसे पुराना ओकटेट नहीं है ( मैं 0 से अधिक है), तो अंतर ऑक्टसब में 256 जोड़ें और डीक्रिएटेड ( ऑक्टफिप ) के अगले ऑक्टेट से 1 घटाएं।
यदि यह सबसे पुराना ऑक्टेट है, तो हमारा घटता हुआ ऑक्टाफ़ाइफ़ , घटाए गए ऑक्टसिप की तुलना में कम है, यानी अंतर नकारात्मक हो जाता है, जो समस्या की स्थिति से नहीं हो सकता है, इस मामले में हम पाश से बाहर निकल जाते हैं -
यदि आपको ऋण देने की आवश्यकता नहीं है, तो परिणाम हमें संतुष्ट करता है। हालांकि, परिणाम किसी भी प्रणाली में 256 के आधार के साथ एक संख्या प्रणाली में प्रस्तुत किया गया है, जो सुविधाजनक नहीं है, क्योंकि हमें एक प्रणाली में आगे की गणना करने की आवश्यकता है जिसे दुभाषिया समझता है। इसलिए, हम परिणामी परिणाम को एक मानक संख्या प्रणाली के लिए मानक तरीके से अनुवादित करते हैं:
... + A i * B i ... + A 3 * B 3 + A 2 * B 2 + A 1 * B 1 + A 0 * B 0 = N B , जहाँ B संख्या प्रणाली का आधार है।
हमारे मामले में: काउंटिप = ऑक्ट्सब नी * 256 एनआई , जहां नी 0 से 3 तक भिन्न होता है, या नी = 3- i , जहां मैं 3 से 0 तक बदलता है, जो आपको मौजूदा चक्र में अनुवाद को शामिल करने की अनुमति देता है। चूंकि संख्या प्रणाली का आधार हमारे पास 2 से अधिक है, फिर डिग्री की गणना करने के लिए, हम 8 की एक बहु का उपयोग करते हैं, क्योंकि बाइनरी प्रतिनिधित्व में 256 100000000 है, अर्थात इकाई को 8 बिट्स बाईं ओर स्थानांतरित कर दिया गया है। इस प्रकार, पहले 0 से, फिर 8 से (कोड के इस भाग में अंतिम महत्वपूर्ण पंक्ति), फिर 16 और 24 तक, हम इस प्रकार 1 (256 0 ), 256, 256 2 और 256 3 से गुणा करते हैं।
दूसरी बार इस साइट पर लौटने से, मुझे कुछ अटपटा लगा, जो कार्यान्वयन के दौरान सरल और समझ में आता था, अब यह अनावश्यक रूप से भ्रमित और जटिल लग रहा था। यह इस कोड का वर्णन करने वाले पाठ की मात्रा से भी आंका जा सकता है।
क्या गलत है? आपको फिर से आवश्यकता क्यों हुई? एक घटाव संचालन के साथ आने के लिए, संख्या आधार में संख्याओं के लिए 256 के आधार के साथ, इन मानों को प्रोग्रामिंग भाषा के लिए समझने योग्य संख्यात्मक रूप में अनुवाद करने के बजाय, और मानक साधनों का उपयोग करते हुए घटाव करने के लिए, खासकर जब से हम अभी भी अनुवाद करते हैं? अंत में, मेरे लिए, मैं इस निष्कर्ष पर पहुंचा कि व्यक्तिपरक मानवीय धारणा ने एक बार फिर एक क्रूर मजाक किया। प्रथम श्रेणी में होने वाले कॉलम में कार्रवाई करने से आसान क्या हो सकता है? कुछ नहीं, क्योंकि यह पहली चीज है जिसे वास्तविक संख्याओं के बाद सभी को सिखाया जाता है। पहली कक्षा से सरलतम ऑपरेशन की तुलना में अनुवाद, बदलाव, जटिल लगते हैं। यह समझना कि यह दशमलव संख्या प्रणाली नहीं है, थोड़ी देर बाद आती है, लेकिन जो कुछ हो रहा है, उसकी गलतता को समझना, जब मुझे दूसरी बार लिखित कोड को देखना था। नतीजतन, उसी साइट का दूसरा संस्करण।

वर .२, सं। १8-२५
 if {[regexp $exip $countip]} then { set octfip [split $countip {.}] set nfip [expr ([lindex $octfip 0] * 0x1000000) + ([lindex $octfip 1] * 0x10000)\ + ([lindex $octfip 2] * 0x100) + ([lindex $octfip 3])] set nsip [expr ([lindex $octsip 0] * 0x1000000) + ([lindex $octsip 1] * 0x10000)\ + ([lindex $octsip 2] * 0x100) + ([lindex $octsip 3])] if {$nfip >= $nsip} then {set countip [expr $nfip - $nsip]} } 

ऑक्टफिप सूची (पहले संस्करण के अनुसार) बनाने के बाद, हम दूसरे तर्क में पते के लिए nfip चर में IPv4 पता मान (जो वे हैं) के अनुरूप संख्या बनाते हैं और पहले तर्क में पते के लिए nsip चर। हम जैसा अनुवाद करते हैं, वैसा ही करते हैं, केवल बिना किसी चक्र के, एक पंक्ति में मानों को प्रतिस्थापित करते हुए: nfip = listitem 0 * 256 3 + listitem 1 * 256 2 + listitem 2 * 256 + listitem 3 , जहां listitem n को सूचीबद्ध करने के लिए संबंधित सूची तत्व है। सीधे लिंडेक्स का उपयोग करते हुए अभिव्यक्ति में। 256, कुछ हद तक, कोड में धारणा की सादगी के लिए गोल हेक्साडेसिमल मान 0x100xxxx के रूप में प्रस्तुत किया जाता है। फिर हम जांचते हैं कि दूसरा तर्क पहले से बड़ा है और दूसरे से पहले को घटाकर, परिणाम में मान को बचाते हुए
नतीजतन, यह थोड़ा आसान था, यह बहुत आसान था। केवल एक चीज जो मुझे इस विकल्प से परेशान करती है, वह है एक्सपीआर गणना में एनएफआईपी और एनएसआईपी चर को ओवरफ्लो करने की काल्पनिक संभावना। हालांकि वर्तमान सी संकलक के लिए, यह डरावना नहीं होना चाहिए। कम्प्यूटेशन और ओवरफ्लो के संबंध में प्रलेखन से http://www.tcl.tk/man/tcl8.5/TclCmd/expr.htm#M23 । संस्करण 8.4 के लिए www.tcl.tk/man/tcl8.4/TclCmd/expr.htm#M5 यह स्पष्ट रूप से कहा गया था कि संख्यात्मक स्थिरांक 32-बिट हस्ताक्षरित संख्याएं हैं, यदि आवश्यक हो, तो 64 बिट हस्ताक्षरित लोगों की व्याख्या की जाएगी, इस उल्लेख के संस्करण 8.5 के लिए कोई। पिछले संस्करण में, अतिप्रवाह की एक काल्पनिक संभावना भी मौजूद थी, लेकिन वहां हमने पहले से ही प्राप्त अंतर को संसाधित किया, जो वास्तविक मामलों में भी 16-बिट संख्या से बहुत कम होगा।
इसके बाद, उपयोगिता का दूसरा भाग शुरू होता है, जिसमें IPv4 पतों की एक आउटपुट सूची बनती है।

वर .2, सं .2-27
 if {[regexp $exdg $countip]} then { puts $startip 

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

वर .2, सं .2-29
 for {set i 0} {$i<$countip} {incr i 1} { set octsip [lreplace $octsip {3} {3} [expr [lindex $octsip {3}] + 1]] 

हम वांछित अनुक्रम के बाकी तत्वों को बनाते हैं, फिर से मैं वास्तव में सरणियों का उपयोग करना चाहता हूं, लेकिन सूची से सरणी तक का अनुवाद इस रूप में सूचियों का उपयोग करने की तुलना में मुझे बहुत बुरा लगता है (यह कैसे सही ढंग से और बस?) किया जा सकता है। यहाँ चर के लिए एक लूप के लिए है जो चलन क्रम के 0 से अधिकतम परिकलित (या दिए गए) तत्व के मानों को चला रहा है। लूप के अंदर, पहले से गठित ऑक्टसिप सूची का अंतिम तत्व (हमारे पते में सबसे कम ऑक्टेट) 1 से बढ़ा है ...

Ver.2, सं .30-36
 for {set j 3} {$j>=0} {incr j -1} { if {[lindex $octsip $j] > 255 && $j > 0} then { set sj [expr $j - 1] set octsip [lreplace $octsip $j $j {0}] set octsip [lreplace $octsip $sj $sj [expr [lindex $octsip $sj] + 1]] } } 

... और हम जाँचते हैं कि क्या अन्य श्रेणियों को समायोजित करना आवश्यक है। इसके लिए, हम 3 से 0. तक के वेरिएबल जे रनिंग वैल्यू वाले लूप के लिए भी आयोजन करते हैं। अगली स्थिति में, हम जांचते हैं कि वर्तमान ऑक्टेट 255 से अधिक है (ओवरफ्लो हुआ है) और यह 0 से अधिक ऑक्टेट j नहीं है, लेकिन 0. के बराबर नहीं है। यदि ओवरफ्लो हुआ है वर्तमान ऑक्टेट शून्य है, उच्च ऑक्टेट में (जो कि ऑक्टसिप सूची मद से इसकी शुरुआत के करीब है), 1. जोड़ें। यदि उच्च ऑक्टेट में अतिप्रवाह हुआ है, तो हम कोई समायोजन नहीं करते हैं ताकि हमारे पास गलत vv4 पता हो।

Ver.2, नंबर 37-44
  set oip [join $octsip {.}] if {[regexp $exip $oip]} then { puts $oip } else { puts ":    " exit 3 } } 

हम अपने पते के ओकटेट वाले परिणामी सूची को एक साथ मर्ज करते हैं, विभाजक एक अवधि है, जो चर चर में शामिल हो। इसके बाद, हम शुरुआत में दिए गए हमारे नियमित अभिव्यक्ति का उपयोग करते हुए, आईपीवी 4 पते से संबंधित परिणाम की जांच करते हैं। यदि सब कुछ सही है - हम कटौती करते हैं, यदि नहीं, तो एक अतिप्रवाह हुआ है या एक और त्रुटि पहले से ही अनुक्रम बनाने की प्रक्रिया में है, निकास निकास आपातकालीन। यह क्षण भी पूरी तरह से सुंदर नहीं है, क्योंकि हमारे पास कई निकास बिंदु हैं, जो यदि हम चाहते हैं, तो उदाहरण के लिए, अंत में समान कार्य करने के लिए असुविधाजनक हो सकता है।
अंतिम समापन ब्रैकेट लूप के लिए अंत है, जो आउटपुट अनुक्रम बनाता है और लाइन 28 पर खुला है।

वेर .2, नंबर 45-51
  } else { puts "    \"$getcountip\"" } } else { puts "   IP  \"$startip\"" } } 

अंतिम लाइनें जिसमें हम 26 और 16 लाइनों की स्थितियों के लिए अन्य शाखाओं पर त्रुटि संदेश प्रदर्शित करते हैं, जहां हम अपेक्षाओं के अनुपालन के लिए प्रोग्राम स्टार्टअप पर दिए गए तर्कों की जांच करते हैं। यह एकमात्र स्थान है जहां गेटकाउंट चर का उपयोग किया जाता है, जो अपरिवर्तित रूप में कार्यक्रम के दूसरे प्राप्त तर्क को संग्रहीत करता है, जो अजीब है और ओवरकिल लगता है, लेकिन इस मामले में एक स्पष्ट (सरल) अन्य विकल्प को लागू करना संभव नहीं था।
दूसरी बार कार्यक्रम के इस भाग के माध्यम से (जहां आउटपुट के लिए अनुक्रम बनता है) को देखते हुए, मैंने पहले सोचा था कि आधार संख्या संख्या में 4-अंकीय संख्याओं का एक पूर्ण योजक और समान संख्याओं के अतिरिक्त कोड में एक अनुवादक को लागू करना अच्छा होगा ताकि आप कर सकें उसी योजक पर घटाव। मैंने अभी तक पहले भाग को नहीं बदला था, और एक कॉलम में गणना की सादगी के बारे में विचारों का प्रभुत्व था। इसे (जंगली) उद्यम लागू करने की इच्छा नहीं हुई, क्योंकि यह अपने आप में दिलचस्प है, लेकिन शायद टीसीएल पर नहीं। यह पहले से ही स्पष्ट था कि दूसरे भाग को पहले के समान शिरा में बदल दिया जाना चाहिए, अर्थात, सामान्य प्रतिनिधित्व से जिसको हमारी आवश्यकता है, उसका अनुवाद करने के लिए (और यह पहले से ही 256-अंकीय संख्या प्रणाली में अनुवाद है)।
गणना की अवधारणा भी बदल गई है, अगर हम लूप की भाषा का उपयोग करके IPv4 पतों पर पुनरावृत्ति कर सकते हैं, तो हमें इस क्रम के आकार की गणना करने की आवश्यकता नहीं है, हम बस एक पते से दूसरी पंक्ति में एक पते पर जाएंगे। इस दृष्टिकोण में भी, यह न केवल हमारे लिए बहुत ही सरल हो गया है, न केवल छोटे से बड़े तक आगे की दिशा में, बल्कि विपरीत दिशा में भी - इसके लिए अतिरिक्त प्रयासों की आवश्यकता नहीं है, हमें बस इसके गठन में लूप चर की वृद्धि को सही ढंग से निर्धारित करने की आवश्यकता है (यहां यह अतिरिक्त कार्यक्षमता के लिए संभव है जो अनुमति देता है) किसी भी दिशा में एक क्रम बनाएं)।

वर .३, सं ० ३-१-३२
 if {$nfip > $minip && $nfip < $maxip} then { if {[set d [expr $nfip >= $nsip]]} then {set di {1}} else {set di {-1}} 

हम nfip के स्वामित्व की जांच करते हैं, जो मुझे याद है, दूसरे तर्क में IPv4 पता होता है, जो कि सीमा को दिए गए नंबर के रूप में होता है (कार्यक्रम की शुरुआत में मिनीप और मैक्सिप निर्धारित किए जाते हैं )। यदि हम सीमा में आते हैं, तो हम पुनरावृत्ति की दिशा निर्धारित करते हैं, यदि दूसरा IPv4 पता nfip पहले nsip (हम पहले से ही संख्या के रूप में पता है) से अधिक है, तो प्रत्यक्ष क्रम में पुनरावृत्ति चर di # 1 है, यदि यह कम है, तो उल्टे क्रम में पुनरावृत्ति, di = -1। तुलना का परिणाम भी में याद किया जाता है।

Ver.3, नंबर 33-37
 for {set i $nsip} {($i<=$nfip && $d) || ($i>=$nfip && !$d)} {incr i $di} { set octip [list [expr ($i & 0xFF000000) >> 24] [expr ($i & 0xFF0000) >> 16]\ [expr ($i & 0xFF00) >> 8] [expr ($i & 0xFF)]] puts [join $octip {.}] } 

हम वेरिएबल में लूप के लिए व्यवस्थित करते हैं जिसका प्रारंभिक मान nsip पर सेट है, और बाहर निकलने की स्थिति को nfip> = nsip के साथ समायोजित किया जाता है, जिसके परिणाम हम d : i <= nfip में संग्रहीत करते हैं यदि हम नीचे से nipip के पास जाते हैं, या फिर i> = nfip । वेतन वृद्धि मैं पहले से ही गणना और di में संग्रहीत है।
लूप के शरीर में, हम IPv4 पते के ऑक्टेट की एक ऑक्टसिप सूची बनाते हैं । यही है, हमें दशमलव संकेतन में इसके संख्यात्मक प्रतिनिधित्व से पता बनाने की आवश्यकता है - इसे 256-दशमलव संख्या प्रणाली में अनुवाद करें। सामान्य मामले में, सिद्धांत का पालन करते हुए, हमें संख्या को एक संख्या प्रणाली में विभाजित करने की आवश्यकता होती है, एक अन्य संख्या प्रणाली के आधार पर और अवशेषों से नई संख्या प्रणाली में एक संख्या बनती है (जिसके आधार पर हम विभाजित होते हैं):
   3 221 225 985 |  256
  -3 221 225 984 |  -----------
  -------------- |  12,582,914 |  256
               1 |  -12,582,912 |  ------- 
                    ---------- |  49 152 |  256
                             2 |  -49 152 |  ---
                                       0 |  192                                                     

परिणाम 192 से शुरू होकर, 0, 2, 1 के उल्टे क्रम में सभी अवशेषों के लिए हमें 192.0.2.1 मिलता है। डिवीजन एक जटिल ऑपरेशन है और कोई अनुकूलन नहीं लाता है, लेकिन हमारे बहुत ही विशेष मामले में: आईपीवी 4 पता और डिवीजन 256 से - सब कुछ बहुत सरल हो जाता है। हम 8 से शिफ्ट होंगे (256 की शक्तियों से विभाजित) और बिट्स को मास्क करें जिनकी हमें ज़रूरत नहीं है (बाइनरी ऑपरेशन "और")। हेक्साडेसिमल रूप में कल्पना करें:
    0xC0000201 |  0xC0000201 |  0xC0000201 |  0xC0000201
   & 0xFF000000 |  & 0x00FF0000 |  & 0x0000FF00 |  & 0x000000FF
  -------------------------------------------------- -------------------
    0xC0000000 >> 24 |  0x00000000 >> 16 |  0x00000200 >> 8 |  0x00000001
  -------------------------------------------------- -------------------
  = 0xC0 (192) |  = 0x00 (0) |  = 0x02 (2) |  = 0x01 (1)

यह सब एक पंक्ति में किया जाता है, प्रत्येक बिट को अपनी सूची तत्व सूची में रखा जाता है। लूप के शरीर में दूसरा बयान, एक संयुक्त सूची प्रदर्शित करता है।

Ver.3, नंबर 38-45
  } else { puts " IP      " exit 3 } } else { puts "   IP  \"$startip\"" } } 

अंतिम लाइनें लगभग अलग नहीं हैं, इसके अलावा, दूसरे तर्क को स्थापित करने में त्रुटि के बारे में निष्कर्ष कार्यक्रम में थोड़ा अधिक स्थानांतरित किया गया है। दूसरे विकल्प की तुलना में कार्यक्रम का पहला भाग भी थोड़ा बदल गया है।

Ver.3, नंबर 1-7
 #!/usr/bin/tclsh8.5 set exip {^(2(5[0-5]|[0-4]\d)|1\d{2}|[1-9]\d{0,1})(\.(2(5[0-5]|[0-4]\d)|1\d{2}|[1-9]\d|\d)){3}$} set exdg {^-?(0?|([1-9]\d*))$} set maxip {0xFFFFFFFF} set minip {0xFFFFFF} 

एक संख्यात्मक पैरामीटर की जांच के लिए नियमित अभिव्यक्ति अब किसी भी लम्बाई के संख्यात्मक मानों के लिए एक सकारात्मक उत्तर देता है, बिना प्रमुख 0 के, लेकिन एक संभावित नकारात्मक संकेत के साथ "-" सामने। यहां हमने चेक को सरल बनाया और सीमाओं का विस्तार किया, क्योंकि परिणामी अनुक्रम की लंबाई को संख्यात्मक रूप में निम्न चर और मिनिप का उपयोग करके चेक किया गया है। exip , , .

.3, №15-20
 set startip [lindex $argv 0] if {![string length [set finiship [lindex $argv 1]]]} then {set finiship {0}} if {[regexp $exip $startip]} then { set octsip [split $startip {.}] set nsip [expr ([lindex $octsip 0] * 0x1000000) + ([lindex $octsip 1] * 0x10000)\ + ([lindex $octsip 2] * 0x100) + ([lindex $octsip 3])] 

8-14 6-12 , . . finiship 0, , . finiship countip , . IPv4 , . nsip .

.3, №21-30
 if {[regexp $exip $finiship]} then { set octfip [split $finiship {.}] set nfip [expr ([lindex $octfip 0] * 0x1000000) + ([lindex $octfip 1] * 0x10000)\ + ([lindex $octfip 2] * 0x100) + ([lindex $octfip 3])] } elseif {[regexp $exdg $finiship] && [expr abs($finiship)] < $maxip} then { set nfip [expr $nsip + $finiship] } else { puts "    \"$finiship\"" exit 5 } 

, — .
elseif , , IPv4 , , . , nfip nsip . IPv4 , ( ).
, IPv4 — exit . , . break , . , , , . getcountipfiniship , , .
(cipl.tl) , IPv4 IPv4 , . , .
> cipl.tl 192.0.2.1 -1
192.0.2.1
192.0.2.0
> cipl.tl 192.0.2.1 192.0.2.0
192.0.2.1
192.0.2.0

, , habrahabr.ru/blogs/complete_code/135340 , , : « , », .

: cipl.zip
wikibooks — ru.wikibooks.org/wiki/_
TCL www.tcl.tk/doc wiki.tcl.tk

Source: https://habr.com/ru/post/In135920/


All Articles