বিভাগের নাম ছাড়াই একটি ফাইল পড়তে কনফিগার পার্সার ব্যবহার করে


90

আমি ConfigParserকোনও স্ক্রিপ্টের রানটাইম কনফিগারেশন পড়তে ব্যবহার করছি ।

আমি কোনও বিভাগের নাম না দেওয়ার নমনীয়তাটি দেখতে চাই (এমন স্ক্রিপ্টগুলি রয়েছে যা যথেষ্ট সহজ; তাদের কোনও 'বিভাগ' দরকার নেই)। ConfigParserএকটি NoSectionErrorব্যতিক্রম ছুঁড়ে ফেলবে , এবং ফাইলটি গ্রহণ করবে না।

আমি কীভাবে কনফিগার পার্সারকে (key, value)বিভাগের নাম ছাড়াই একটি কনফিগার ফাইলের টিপলগুলি পুনরুদ্ধার করতে পারি ?

এই ক্ষেত্রে:

key1=val1
key2:val2

আমি বরং কনফিগার ফাইলে লিখতে চাই না।


উত্তর:


53

অ্যালেক্স মার্টেলি ফাইলগুলি পার্স করার জন্য একটি সমাধান সরবরাহ করেছিলেন (যা দৃশ্যত বিভাগ-কম কনফিগার ফাইল রয়েছে)।ConfigParser.properties

তার সমাধানটি একটি ফাইলের মতো মোড়ক যা স্বয়ংক্রিয়ভাবে একটি প্রয়োজনীয় ডামি বিভাগ সন্নিবেশ করবে যা ConfigParserএর প্রয়োজনীয়তাগুলি পূরণ করে।


+1 কারণ এটি হ'ল আমি যা প্রস্তাব করতে চলেছিলাম। আপনার সমস্ত করণীয় যখন কেবলমাত্র একটি বিভাগ যুক্ত করুন তখন সমস্ত জটিলতা যুক্ত করুন কেন!
জ্যাথানিজম

4
@ জ্যাথানিজম: এমন কিছু ক্ষেত্রে রয়েছে যেখানে আপনি বিদ্যমান কনফিগারেশন / বৈশিষ্ট্যগুলির ফাইলগুলির সাথে কাজ করতে চান, যা বিদ্যমান জাভা কোড দ্বারা পড়া হয় এবং আপনি এই শিরোনামগুলির সংশোধন করার ঝুঁকি জানেন না
tthepang

44

জেটেরাস দ্বারা এই উত্তর দ্বারা আলোকিত , আমি এই সমাধানটি নিয়ে আসছি:

  1. একটি স্ট্রিং মধ্যে পুরো ফাইল পড়ুন
  2. একটি ডিফল্ট বিভাগের নাম সহ উপসর্গ
  3. কোনও ফাইলের মতো বস্তুর নকল করতে স্ট্রিংআইও ব্যবহার করুন
ini_str = '[root]\n' + open(ini_path, 'r').read()
ini_fp = StringIO.StringIO(ini_str)
config = ConfigParser.RawConfigParser()
config.readfp(ini_fp)


ভবিষ্যতের গুগলারের জন্য সম্পাদনা করুন : পাইথন ৩.৪++ অবমূল্যায়ন readfpকরা হয়েছে এবং এর StringIOদরকার নেই। পরিবর্তে আমরা read_stringসরাসরি ব্যবহার করতে পারি :

with open('config_file') as f:
    file_content = '[dummy_section]\n' + f.read()

config_parser = ConfigParser.RawConfigParser()
config_parser.read_string(file_content)

এটি একটি সাধারণ মেকফিল (কেবলমাত্র এলিয়াস সহ) পার্স করতে বিস্ময়কর কাজ করে! এই উত্তরের দ্বারা অনুপ্রাণিত পাইথনে তাদের সম্পূর্ণ কমান্ড দ্বারা উপকরনগুলি প্রতিস্থাপনের জন্য এখানে একটি সম্পূর্ণ স্ক্রিপ্ট রয়েছে
চমত্কার

42

আপনি কোডের একক লাইনে এটি করতে পারেন।

পাইথন 3, শুরুতে যোগ আপনার কনফিগ ফাইল ডেটাতে একটি জাল বিভাগ হেডার, এবং এটি পাস ইন read_string()

from configparser import ConfigParser

parser = ConfigParser()
with open("foo.conf") as stream:
    parser.read_string("[top]\n" + stream.read())  # This line does the trick.

আপনি এর itertools.chain()জন্য একটি বিভাগ শিরোনাম অনুকরণ করতেও ব্যবহার করতে পারেন read_file()। এটি উপরোক্ত পদ্ধতির চেয়ে মেমরির চেয়ে দক্ষ হতে পারে, যদি আপনার রান-টাইম পরিবেশে একটি বড় কনফিগারেশন ফাইল থাকে তবে এটি সহায়ক হতে পারে।

from configparser import ConfigParser
from itertools import chain

parser = ConfigParser()
with open("foo.conf") as lines:
    lines = chain(("[top]",), lines)  # This line does the trick.
    parser.read_file(lines)

অজগর 2 এ, আপনার কনফিগার ফাইলের ডেটাতে একটি নকল বিভাগের শিরোলেখ প্রস্তুত করুন, ফলাফলটিকে কোনও StringIOবস্তুতে মুড়িয়ে দিন এবং এতে পাস করুন readfp()

from ConfigParser import ConfigParser
from StringIO import StringIO

parser = ConfigParser()
with open("foo.conf") as stream:
    stream = StringIO("[top]\n" + stream.read())  # This line does the trick.
    parser.readfp(stream)

এর যে কোনও পদ্ধতির সাথে আপনার কনফিগারেশন সেটিংস পাওয়া যাবে parser.items('top')

আপনি পাইথন 3 তে স্ট্রিংআইও ব্যবহার করতে পারেন, সম্ভবত পুরানো এবং নতুন পাইথন উভয় অনুবাদকের সাথে সামঞ্জস্যের জন্য, তবে নোট করুন যে এটি এখন ioপ্যাকেজে বাস করে এবং readfp()এখন অবচয়হীন।

বিকল্পভাবে, আপনি কনফিগার পার্সারের পরিবর্তে একটি টোমল পার্সার ব্যবহার বিবেচনা করতে পারেন ।


18

এটি সাধারণভাবে করার জন্য আপনি কনফিগারবজ লাইব্রেরিটি ব্যবহার করতে পারেন: http://www.voidspace.org.uk/python/configobj.html

আপডেট হয়েছে: সর্বশেষ কোড এখানে সন্ধান করুন

আপনি যদি ডেবিয়ান / উবুন্টুর অধীনে থাকেন তবে আপনি আপনার প্যাকেজ ম্যানেজারটি ব্যবহার করে এই মডিউলটি ইনস্টল করতে পারেন:

apt-get install python-configobj

ব্যবহারের একটি উদাহরণ:

from configobj import ConfigObj

config = ConfigObj('myConfigFile.ini')
config.get('key1') # You will get val1
config.get('key2') # You will get val2

8

এটি করার সবচেয়ে সহজ উপায়টি হল আমার মতে পাইথনের সিএসভি পার্সার ব্যবহার করা। এখানে একটি পড়ার / লেখার ফাংশনটি এই পদ্ধতির পাশাপাশি পরীক্ষক ড্রাইভারকে প্রদর্শন করে। মানগুলি মাল্টি-লাইন হওয়ার অনুমতি না দেওয়া হলে এটি কাজ করবে। :)

import csv
import operator

def read_properties(filename):
    """ Reads a given properties file with each line of the format key=value.  Returns a dictionary containing the pairs.

    Keyword arguments:
        filename -- the name of the file to be read
    """
    result={ }
    with open(filename, "rb") as csvfile:
        reader = csv.reader(csvfile, delimiter='=', escapechar='\\', quoting=csv.QUOTE_NONE)
        for row in reader:
            if len(row) != 2:
                raise csv.Error("Too many fields on row with contents: "+str(row))
            result[row[0]] = row[1] 
    return result

def write_properties(filename,dictionary):
    """ Writes the provided dictionary in key-sorted order to a properties file with each line of the format key=value

    Keyword arguments:
        filename -- the name of the file to be written
        dictionary -- a dictionary containing the key/value pairs.
    """
    with open(filename, "wb") as csvfile:
        writer = csv.writer(csvfile, delimiter='=', escapechar='\\', quoting=csv.QUOTE_NONE)
        for key, value in sorted(dictionary.items(), key=operator.itemgetter(0)):
                writer.writerow([ key, value])

def main():
    data={
        "Hello": "5+5=10",
        "World": "Snausage",
        "Awesome": "Possum"
    }

    filename="test.properties"
    write_properties(filename,data)
    newdata=read_properties(filename)

    print "Read in: "
    print newdata
    print

    contents=""
    with open(filename, 'rb') as propfile:
        contents=propfile.read()
    print "File contents:"
    print contents

    print ["Failure!", "Success!"][data == newdata]
    return

if __name__ == '__main__': 
     main() 

csvসাধারণ ConfigParserঅভিযোগটি সমাধানের জন্য মডিউলটির চতুর ব্যবহার । সহজেই আরও সাধারণীকরণ করা হয় এবং পাইথন 2 এবং 3 উভয়ই সামঞ্জস্যপূর্ণ হয়
মার্টিনো

6

এই সমস্যায় আমি নিজেই প্রবেশ করে, আমি কনফিগারপারসার (পাইথন 2 এর সংস্করণ) -এর জন্য একটি সম্পূর্ণ মোড়ক লিখেছি যা স্বীকৃত উত্তরের সাথে যুক্ত অ্যালেক্স মার্তেলির পদ্ধতির ভিত্তিতে স্বচ্ছভাবে বিভাগগুলি ছাড়াই ফাইলগুলি পড়তে এবং লিখতে পারে। এটি কনফিগার পার্সারের যে কোনও ব্যবহারের জন্য একটি ড্রপ-ইন প্রতিস্থাপন হওয়া উচিত। এটির যে কোনও প্রয়োজনে যদি এই পৃষ্ঠাটি সন্ধান করে তবে এটি পোস্ট করা।

import ConfigParser
import StringIO

class SectionlessConfigParser(ConfigParser.RawConfigParser):
    """
    Extends ConfigParser to allow files without sections.

    This is done by wrapping read files and prepending them with a placeholder
    section, which defaults to '__config__'
    """

    def __init__(self, *args, **kwargs):
        default_section = kwargs.pop('default_section', None)
        ConfigParser.RawConfigParser.__init__(self, *args, **kwargs)

        self._default_section = None
        self.set_default_section(default_section or '__config__')

    def get_default_section(self):
        return self._default_section

    def set_default_section(self, section):
        self.add_section(section)

        # move all values from the previous default section to the new one
        try:
            default_section_items = self.items(self._default_section)
            self.remove_section(self._default_section)
        except ConfigParser.NoSectionError:
            pass
        else:
            for (key, value) in default_section_items:
                self.set(section, key, value)

        self._default_section = section

    def read(self, filenames):
        if isinstance(filenames, basestring):
            filenames = [filenames]

        read_ok = []
        for filename in filenames:
            try:
                with open(filename) as fp:
                    self.readfp(fp)
            except IOError:
                continue
            else:
                read_ok.append(filename)

        return read_ok

    def readfp(self, fp, *args, **kwargs):
        stream = StringIO()

        try:
            stream.name = fp.name
        except AttributeError:
            pass

        stream.write('[' + self._default_section + ']\n')
        stream.write(fp.read())
        stream.seek(0, 0)

        return ConfigParser.RawConfigParser.readfp(self, stream, *args,
                                                   **kwargs)

    def write(self, fp):
        # Write the items from the default section manually and then remove them
        # from the data. They'll be re-added later.
        try:
            default_section_items = self.items(self._default_section)
            self.remove_section(self._default_section)

            for (key, value) in default_section_items:
                fp.write("{0} = {1}\n".format(key, value))

            fp.write("\n")
        except ConfigParser.NoSectionError:
            pass

        ConfigParser.RawConfigParser.write(self, fp)

        self.add_section(self._default_section)
        for (key, value) in default_section_items:
            self.set(self._default_section, key, value)

5

ব্লুয়াসফিল্ডের উত্তরে কনফিগারবজ উল্লেখ করা হয়েছে, তবে মূল লিব কেবল পাইথন ২ সমর্থন করে It এটিতে এখন পাইথন 3+ সামঞ্জস্যপূর্ণ বন্দর রয়েছে:

https://github.com/DiffSK/configobj

API গুলি পরিবর্তন হয়নি, দেখুন এটি ডক


যদিও এই লিঙ্কটি প্রশ্নের উত্তর দিতে পারে, উত্তরের প্রয়োজনীয় অংশগুলি এখানে অন্তর্ভুক্ত করা এবং রেফারেন্সের জন্য লিঙ্কটি সরবরাহ করা ভাল। লিঙ্কযুক্ত উত্তর পরিবর্তিত হলে লিঙ্কযুক্ত উত্তরগুলি অবৈধ হতে পারে। - পর্যালোচনা থেকে
ks

এবং যদি এপিআই পরিবর্তন হয়? পুরানো হয়ে থাকলে উত্তরটি আপনি সর্বদা সম্পাদনা করতে পারবেন, এটি কোনও লিঙ্ক বা কোড স্নিপেট হোক। আমি বহুবার এটি করেছি, আপনি কেন এটি সমস্যা মনে করেন তা আমি দেখতে পাচ্ছি না।
laike9m
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.