python - पायथन: फ़ाइल में पढ़ने पर#comment लाइनों को अनदेखा कैसे करें




string file-io (6)

आप startswith() उपयोग कर सकते हैं

जैसे

for line in open("file"):
    li=line.strip()
    if not li.startswith("#"):
        print line.rstrip()

https://code.i-harness.com

पायथन में, मैंने सिर्फ एक पंक्ति फ़ाइल को एक टेक्स्ट फ़ाइल पढ़ी है और मैं जानना चाहता हूं कि पंक्ति की शुरुआत में हैश # के साथ टिप्पणियों को अनदेखा करने के लिए कोड कैसे करें।

मुझे लगता है कि यह ऐसा कुछ होना चाहिए:

for 
   if line !contain #
      then ...process line
   else end for loop 

लेकिन मैं पाइथन के लिए नया हूं और मुझे वाक्यविन्यास नहीं पता है


एक फ़िल्टरिंग अभिव्यक्ति का एक अधिक कॉम्पैक्ट संस्करण भी इस तरह दिख सकता है:

for line in (l for l in open(filename) if not l.startswith('#')):
    # do something with line

(l for ... ) को "जेनरेटर एक्सप्रेशन" कहा जाता है जो यहां एक रैपिंग इटरेटर के रूप में कार्य करता है जो इसे ओवरराइड करते समय फ़ाइल से सभी अनियंत्रित लाइनों को फ़िल्टर करेगा। स्क्वायर ब्रैकेट्स [l for ... ] में एक ही चीज़ के साथ भ्रमित न करें [l for ... ] जो एक "सूची समझ" है जो पहले फाइल से सभी लाइनों को स्मृति में पढ़ेगी और केवल तभी इसे फिर से शुरू कर देगी।

कभी-कभी आप इसे कम एक-पंक्तिबद्ध और अधिक पठनीय रखना चाहते हैं:

lines = open(filename)
lines = (l for l in lines if ... )
# more filters and mappings you might want
for line in lines:
    # do something with line

सभी फिल्टर एक पुनरावृत्ति में फ्लाई पर निष्पादित किए जाएंगे।


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

# Comment line 1
# Comment line 2

# host01  # This host commented out.
host02  # This host not commented out.
host03
  host04  # Oops! Included leading whitespace in error!

निकलेगा:

host02
host03
host04

यहां दस्तावेज़ कोड है, जिसमें एक डेमो शामिल है:

def strip_comments(item, *, token='#'):
    """Generator. Strips comments and whitespace from input lines.

    This generator strips comments, leading/trailing whitespace, and
    blank lines from its input.

    Arguments:
        item (obj):  Object to strip comments from.
        token (str, optional):  Comment delimiter.  Defaults to ``#``.

    Yields:
        str:  Next non-blank line from ``item`` with comments and
            leading/trailing whitespace removed.

    """

    for line in item:
        s = line.split(token, 1)[0].strip()
        if s != '':
            yield s


if __name__ == '__main__':
    HOSTS = """# Comment line 1
    # Comment line 2

    # host01  # This host commented out.
    host02  # This host not commented out.
    host03
      host04  # Oops! Included leading whitespace in error!""".split('\n')


    hosts = strip_comments(HOSTS)
    print('\n'.join(h for h in hosts))

सामान्य उपयोग केस एक फ़ाइल से टिप्पणियों को पट्टी करना होगा (यानी, एक होस्ट फ़ाइल, जैसा ऊपर मेरे उदाहरण में है)। यदि यह मामला है, तो उपरोक्त कोड की पूंछ अंत में संशोधित किया जाएगा:

if __name__ == '__main__':
    with open('hosts.txt', 'r') as f:
        hosts = strip_comments(f)

    for host in hosts:
        print('\'%s\'' % host)

मैं अनुशंसा करता हूं कि जब आप # वर्ण देखेंगे तो आप पूरी लाइन को अनदेखा न करें; बस बाकी रेखा को अनदेखा करें। आप आसानी से partition नामक स्ट्रिंग विधि फ़ंक्शन के साथ ऐसा कर सकते हैं:

with open("filename") as f:
    for line in f:
        line = line.partition('#')[0]
        line = line.rstrip()
        # ... do something with line ...

partition एक tuple देता है: विभाजन स्ट्रिंग से पहले सब कुछ, विभाजन स्ट्रिंग, और विभाजन स्ट्रिंग के बाद सबकुछ। तो, [0] साथ अनुक्रमण करके हम विभाजन स्ट्रिंग से पहले भाग लेते हैं।

संपादित करें: यदि आप पाइथन के एक संस्करण का उपयोग कर रहे हैं जिसमें partition() नहीं है, तो यहां वह कोड है जिसका आप उपयोग कर सकते हैं:

with open("filename") as f:
    for line in f:
        line = line.split('#', 1)[0]
        line = line.rstrip()
        # ... do something with line ...

यह स्ट्रिंग को '#' वर्ण पर विभाजित करता है, फिर विभाजन से पहले सबकुछ रखता है। 1 तर्क एक विभाजन के बाद .split() विधि रोकता है; चूंकि हम केवल 0 वें सबस्ट्रिंग को पकड़ रहे हैं ( [0] साथ अनुक्रमणित करके) आपको 1 तर्क के बिना एक ही जवाब मिल जाएगा, लेकिन यह थोड़ा तेज़ हो सकता है। (@gnr से एक टिप्पणी के लिए मेरे मूल कोड से सरलीकृत। मेरा मूल कोड कोई अच्छा कारण नहीं था; धन्यवाद, @gnr।)

आप partition() का अपना संस्करण भी लिख सकते हैं partition() । यहां एक part() कहा जाता है part() :

def part(s, s_part):
    i0 = s.find(s_part)
    i1 = i0 + len(s_part)
    return (s[:i0], s[i0:i1], s[i1:])

@dalle ने नोट किया कि '#' एक स्ट्रिंग के अंदर दिखाई दे सकता है। इस मामले को सही ढंग से संभालना इतना आसान नहीं है, इसलिए मैंने इसे अनदेखा किया, लेकिन मुझे कुछ कहना चाहिए था।

यदि आपकी इनपुट फ़ाइल में उद्धृत तारों के लिए पर्याप्त नियम हैं, तो यह मुश्किल नहीं है। यदि आप किसी भी कानूनी पायथन उद्धृत स्ट्रिंग को स्वीकार करते हैं तो यह कठिन होगा, क्योंकि एकल-उद्धृत, डबल-उद्धृत, मल्टीलाइन उद्धरण हैं जो बैकस्लैश के अंत में लाइन से बचते हैं, ट्रिपल उद्धृत तार (या तो सिंगल या डबल कोट्स का उपयोग करके), और कच्चे तार भी! एक जटिल राज्य मशीन होगी जो सही ढंग से सभी को संभालने का एकमात्र संभावित तरीका है।

लेकिन अगर हम खुद को केवल एक साधारण उद्धृत स्ट्रिंग तक सीमित करते हैं, तो हम इसे एक साधारण राज्य मशीन से संभाल सकते हैं। हम स्ट्रिंग के अंदर बैकस्लैश-उद्धृत डबल कोट भी अनुमति दे सकते हैं।

c_backslash = '\\'
c_dquote = '"'
c_comment = '#'


def chop_comment(line):
    # a little state machine with two state varaibles:
    in_quote = False  # whether we are in a quoted string right now
    backslash_escape = False  # true if we just saw a backslash

    for i, ch in enumerate(line):
        if not in_quote and ch == c_comment:
            # not in a quote, saw a '#', it's a comment.  Chop it and return!
            return line[:i]
        elif backslash_escape:
            # we must have just seen a backslash; reset that flag and continue
            backslash_escape = False
        elif in_quote and ch == c_backslash:
            # we are in a quote and we see a backslash; escape next char
            backslash_escape = True
        elif ch == c_dquote:
            in_quote = not in_quote

    return line

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


मैं उपयोग करते हैं

for line  in lines:
    if '#' not in line:
        #do something

यह पूरी लाइन को अनदेखा कर देगा, हालांकि उत्तर में जिसमें विभाजन शामिल है, मेरा अपवर्त है क्योंकि इसमें # से पहले की कोई जानकारी शामिल हो सकती है


मैंने हाल ही में पाया है कि जनरेटर फ़ंक्शन इस का एक अच्छा काम करता है। मैंने टिप्पणी लाइनों, खाली लाइनों आदि को छोड़ने के लिए समान कार्यों का उपयोग किया है।

मैं अपने कार्य को परिभाषित करता हूं

def skip_comments(file):
    for line in file:
        if not line.strip().startswith('#'):
            yield line

इस तरह, मैं बस कर सकता हूँ

f = open('testfile')
for line in skip_comments(f):
    print line

यह मेरे सभी कोड में पुन: प्रयोज्य है, और मैं कोई अतिरिक्त हैंडलिंग / लॉगिंग / आदि जोड़ सकता हूं। जिसकी मुझे आवश्यकता है।





skip