2017-09-15 17 views
8

में किसी सूची से आईपी और पोर्ट निकालें I लौटाई गई सूची से आईपी और पोर्ट निकालना चाहते हैं। मैं वर्तमान में अतिरिक्त वर्णों को हटाने के लिए str (var) .replace कमांड का उपयोग कर रहा हूं। यह/समस्याओं का कारण है जाएगा जब स्ट्रिंग प्रारूप एक त्रुटिपायथन 3.x

def discover_device(): 
    """ This function will look for available device on the local network and extract the IP from the result""" 
    discover_device = '[<Device: 192.168.222.123:8075>]' # Actually: call to broadcasting device 
    device_ip = str(discover_device).replace('[<Device: ', '').replace(':8075>]', '') 

के माध्यम से .replace आदेश बनाने तो समस्या है, तो आएगा परिवर्तन: [<Device: xxx.xxx.xxx.xxx:xxxx>]

यह करने के लिए परिवर्तित: [<now_what: xxx.xxx.xxx.xxx:xxxx>]

dicovery_device() के माध्यम से और त्रुटि होगी।

आईपी/पोर्ट पैटर्न की पहचान करने और आसपास के पात्रों की अखंडता पर भरोसा किए बिना आईपी और पोर्ट निकालने का सबसे अच्छा अभ्यास क्या है?

इस से: 192.168.222.123:8075

और अच्छा होगा यदि: [<Device: 192.168.222.123:8075>]

इस के लिए

[192.168.222.123, 8075]

विचार आईपी में रखते हुए डॉट ब्लॉक और सबसे बड़ा बंदरगाह नंबर पर 16-बिट (सामान्य रूप से 4 पूर्णांकों आधारित भीतर प्रसरण कोलन के बाद 5 पूर्णांक तक)

+0

तो यदि आपका इनपुट ''[<डिवाइस: 192.168.222.123:8075>]' 'आप' 1 9 2.168.222.123: 8075' भाग निकालना चाहते हैं? – RagingRoosevelt

+0

हां, लेकिन आदर्श रूप से दो अलग-अलग चर ip_var और port_var में। मैं आपकी टिप्पणी को दर्शाने के लिए अपना प्रश्न संपादित करूंगा। धन्यवाद! –

+2

चूंकि यह प्रश्न भावी-प्रूफिंग के बारे में पूछ रहा है, ऐसा लगता है कि सबसे अच्छे उत्तर में आईपीवी 6 पते को संभालने में भी शामिल होगा, साथ ही, * वास्तव में * चीज़ों को पकाएं, क्योंकि उनमें ':' वर्ण शामिल हैं। –

उत्तर

3

आईपीवी 4 पता मानते हुए, संख्याओं और महत्वपूर्ण विराम चिह्न निकालने का प्रयास करें। फिर आवश्यक होने पर वैध परिणाम का टुकड़ा करें। आईपी ​​पते को भी मान्य करना एक सुरक्षित दृष्टिकोण हो सकता है।

अजगर 3 में:

कोड

import string 
import ipaddress 


def validate_port(func): 
    """Return the results or raise and exception for invalid ports.""" 
    def wrapper(arg): 
     result = func(arg) 
     if len(result) == 2 and not result[-1].isdigit(): 
      raise ValueError("Invalid port number.") 
     return result 
    return wrapper 


@validate_port 
def discover_device(device): 
    """Return a list of ip and optional port number. Raise exception for invalid ip.""" 
    result = "".join(i for i in device if i in (string.digits +".:")).strip(":").split(":") 

    try: 
     ipaddress.ip_address(result[0]) 
    except ValueError as e: 
     # Numbers in the device name (index 0) or invalid ip 
     try: 
      ipaddress.ip_address(result[1]) 
     except IndexError: 
      raise e 
     else: 
      return result[1:] 
    else: 
     return result 

डेमो

discover_device("[<Device: 192.168.222.123>]") 
# ['192.168.222.123'] 

discover_device("[<Device: 192.168.222.123:8075>]") 
# ['192.168.222.123', '8075'] 

discover_device("[<Device.34: 192.168.222.123:8080>]") 
# ['192.168.222.123', '8080'] 

discover_device("[<Device: 192.168.222123>]") 
# ValueError: '192.168.222123' does not appear to be an IPv4 or IPv6 address 

discover_device("[<Device21: 192.168.222123>]") 
# ValueError: '192.168.222123' does not appear to be an IPv4 or IPv6 address 

discover_device("[<device.451: 192.168.222.123:80.805>]") 
# ValueError: Invalid port number. 

विशेषताएं

  • असंवेदनशील आसपास के पात्रों
  • आईपी पते का सत्यापन (नहीं IPv6) और अपवाद
  • सत्यापित करें पोर्ट संख्या उपकरण का नाम संख्या के खिलाफ
  • रक्षा से निपटने (वैकल्पिक)

विवरण के लिए

आमतौर पर result एक है आईपी ​​और एक वैकल्पिक पोर्ट नंबर शामिल सूची। हालांकि, ऐसे मामलों में जहां डिवाइस नाम में संख्याएं हैं, परिणाम की पहली अनुक्रमणिका में अवांछित संख्याएं शामिल होंगी। यहाँ result के उदाहरण हैं: उपकरण का नाम संख्या के लिए

# ['192.168.222.123']         ip 
    # ['192.168.222.123', '8075']       ip, port 
    # ['192.168.222123']         invalid ip 
    # ['.34', '192.168.222.123', '8080']     device #, ip, port 
    # ['192.168.222.123', '80.805']      invalid port 

अपवाद हैंडलिंग परीक्षण और पहली या दूसरी सूचकांकों में आई पी पतों को सत्यापित करता है।यदि कोई नहीं मिला है, तो एक अपवाद उठाया जाता है।

हालांकि पोर्ट नंबर मान्य करना प्रश्न के दायरे से बाहर है, बंदरगाहों को एक संख्या माना जाता है। validate_port सजावटी में एक साधारण परीक्षण जोड़ा गया था, जिसे वांछित के रूप में लागू या अपडेट किया जा सकता है। सजावटी discover_device() से आउटपुट स्क्रीन करता है। यदि बंदरगाह शुद्ध संख्या नहीं है, तो एक अपवाद उठाया जाता है। प्रतिबंधों को संशोधित करने के लिए this post देखें। पायथन सजावट पर एक महान ट्यूटोरियल के लिए this blog देखें।

विकल्प

तो सत्यापन एक चिंता का विषय, निम्नलिखित कोड पर्याप्त होना चाहिए नहीं है, बशर्ते "." डिवाइस नाम से अनुपस्थित है:

def discover_device(device): 
    result = "".join(i for i in device if i in (string.digits +".:")).strip(":").split(":") 
    if "." not in result[0]: 
     return result[1:] 
    return result 

एक गैर डेकोरेटर समाधान है पसंदीदा, निम्न फ़ंक्शन को परिभाषित करें:

def validate_port(result): 
    """Return the results or raise and exception for invalid ports.""" 
     if len(result) == 2 and not result[-1].isdigit(): 
      raise ValueError("Invalid port number.") 
     return result 

अब बाद के फ़ंक्शन में discover_device() के वापसी मूल्यों को पास करें, यानी return validate_port(result[1:]) और return validate_port(result)

सुझावों के लिए @ कोडर के संबंध में।

+0

धन्यवाद। अब यह आईपीएस और वैकल्पिक बंदरगाहों के लिए काम करता है। – pylang

+0

Thx @coder। आपके एज केस के बाद पोस्ट में सुधार हुआ है। – pylang

+0

मुझे पसंद है कि आप कैसे सोचते हैं @coder। पायथन 3 के 'ipaddress' मॉड्यूल का उपयोग कर आईपी सत्यापन जोड़ा गया। मेरे सुझावों पर विचार करने के लिए – pylang

2

आप आईपी पता, स्वतंत्रता खोजने के लिए बस regex का उपयोग कर सकते हैं पहले से क्या y।

उदाहरण इस एक के लिए:

\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b 

एक परीक्षण के रूप:

>>> import re 
>>> re.findall(r'\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b', '[<Device: 192.168.222.123:8075>]') 
['192.168.222.123'] 
>>> re.findall(r'\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b', '[<SomethingElse: 192.168.222.123:8075>]') 
['192.168.222.123'] 
>>> re.findall(r'\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{,5}', '[<SomethingElse: 192.168.222.123:8075>]') 
['192.168.222.123:8075'] 
+1

एक प्रश्न, क्योंकि एक बंदरगाह लंबाई में 5 अंक हो सकता है "\ d {, 4}" हो सकता है "\ d {, 5}" क्या इसका मतलब 5 से 5 तक नहीं होगा? - धन्यवाद –

+0

@EnriqueBruzual: हाँ वास्तव में –

4

कोई regex इस के लिए आवश्यक है। str की अंतर्निहित विधि split का उपयोग करें।

>>> device = '[<Device: 192.168.222.123:8075>]' 
>>> _, ip, port = device.strip('[<>]').split(':') 
>>> print((ip.strip(), port)) 
('192.168.222.123', '8075') 

तुम सच में एक regex का उपयोग करना चाहते है, मैं का प्रयोग करेंगे एक सरल एक:

>>> import re 
>>> ip, port = re.findall('([\d.]+)', device) 
>>> print((ip, port)) 
('192.168.222.123', '8075') 
+0

यह पहले कॉलन मौजूद होने पर निर्भर करता है, हालांकि। यदि इनपुट ओपी के उदाहरण की तुलना में अधिक तेज़ी से बदल दिया गया था, तो आपके पास '' [] '' या ''[<डिवाइस 192.168.222.123:8075>]' या' '[(डिवाइस: 1 9 2.168.222.123:8075)]' 'जो आपके उदाहरण में टूट जाएगा। – RagingRoosevelt

+0

@RagingRoosevelt: OP ने बताया कि डिवाइस का नाम '[]' रूप में बदल सकता है। मेरा जवाब इसके लिए भी काम करता है। एक जवाब को हर मामले के लिए कल्पना करने की आवश्यकता नहीं है; यह इस विशिष्ट प्रश्न के लिए है। यदि ओपी किसी अन्य रूप में डिवाइस का नाम रखने की अपेक्षा करता है, तो मैं अपना जवाब बदल दूंगा। –

+0

यदि आप फिर से प्रश्न पढ़ते हैं, तो ओपी ने कभी निर्दिष्ट नहीं किया कि उस डिवाइस का नाम उस स्ट्रिंग के बारे में क्या बदल गया था (वास्तव में, यह एक धारणा थी जिसे आपने पेश किया था)। ओपी केवल निर्दिष्ट "यह त्रुटि/कारणों का कारण बनता है जब स्ट्रिंग प्रारूप त्रुटि के माध्यम से .replace कमांड को बदलता है"। ओपी ने ** ** का एक उदाहरण प्रदान किया जिस प्रारूप में प्रारूप बदल सकता है। – RagingRoosevelt

-1

मुझे लगता है कि आपका सर्वश्रेष्ठ दांव रेगुलर एक्सप्रेशन का उपयोग करने के लिए है:

import re 

def discover_device(in_str): 
    m = re.search('(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(?:\:\d{1,5})?)', in_str) 
    if m: 
     return m.group(0) 
    else: 
     return None 

यदि आपकी रेगेक्स स्ट्रिंग (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(?:\:\d{1,5})?) है, तो ब्रेकडाउन है:

  • \d{1,3}\. 1 और 3 के बीच की अवधि
  • (?:\:\d{1,5})? अर्धविराम से एक या शून्य घटनाओं 1 से 5 के बीच और संख्याएं आती हैं के लिए लग रहा है, जिसके बाद अंकों के लिए लग रहा है (?: यह बताता है कि यह एक गैर पर कब्जा समूह है इतना है कि यह जीत हासिल की 'टी अपने परिणाम में अपने आप में उपस्थित होना)

तो आप अलग से बंदरगाह और आईपी कब्जा करने के लिए यह चाहते थे, तुम कर सकते हो

def discover_device(in_str): 
    m = re.search('(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?:\:(\d{1,5}))?', in_str) 
    if m: 
     return (m.group(1), m.group(2)) 
    else: 
     return None 

Here's यदि आप इसके साथ खेलना चाहते हैं तो रेगेक्स।

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