2012-03-16 10 views
11

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

समस्या यह है कि एक संपत्ति के पेड़ के इनपुट पक्ष पर, उपयोगकर्ता हैं, और वे कॉन्फ़िगरेशन फ़ाइलों को संशोधित कर सकते हैं। एक बूलियन मान की तरह, कई तरीकों से में निर्दिष्ट किया जा सकता है:

dosomething.enabled=true 
dosomething.enabled=trUE 
dosomething.enabled=yes 
dosomething.enabled=ON 
dosomething.enabled=1 

डिफ़ॉल्ट व्यवहार है 0 या 1 के लिए जाँच करने के लिए और फिर

std::ios_base::boolalpha 

का उपयोग स्ट्रीम प्राप्त करने के पार्स करने के लिए प्रयास करने के लिए मौजूदा लोकेल के लिए उचित तरीके से मूल्य ... जो कि हम अंतरराष्ट्रीय ग्राहकों को कॉन्फ़िगरेशन फ़ाइल भेजने का प्रयास करते हैं, जो पागल हो सकते हैं।

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

धन्यवाद!

उत्तर

18

आप boost::property_tree::translator_between विशेषज्ञ ताकि एक संपत्ति पेड़ एक bool मान प्रकार के लिए एक कस्टम अनुवादक का उपयोग करेगा कर सकते हैं। अनुकूलित विशेषज्ञता चाहते ग्राहकों द्वारा यह विशेषज्ञता दिखाई देनी चाहिए (यानी #includ एड)। यहाँ एक काम कर उदाहरण है:

#include <iostream> 
#include <boost/property_tree/ptree.hpp> 
#include <boost/property_tree/json_parser.hpp> 
#include <boost/algorithm/string/predicate.hpp> 

// Custom translator for bool (only supports std::string) 
struct BoolTranslator 
{ 
    typedef std::string internal_type; 
    typedef bool  external_type; 

    // Converts a string to bool 
    boost::optional<external_type> get_value(const internal_type& str) 
    { 
     if (!str.empty()) 
     { 
      using boost::algorithm::iequals; 

      if (iequals(str, "true") || iequals(str, "yes") || str == "1") 
       return boost::optional<external_type>(true); 
      else 
       return boost::optional<external_type>(false); 
     } 
     else 
      return boost::optional<external_type>(boost::none); 
    } 

    // Converts a bool to string 
    boost::optional<internal_type> put_value(const external_type& b) 
    { 
     return boost::optional<internal_type>(b ? "true" : "false"); 
    } 
}; 

/* Specialize translator_between so that it uses our custom translator for 
    bool value types. Specialization must be in boost::property_tree 
    namespace. */ 
namespace boost { 
namespace property_tree { 

template<typename Ch, typename Traits, typename Alloc> 
struct translator_between<std::basic_string< Ch, Traits, Alloc >, bool> 
{ 
    typedef BoolTranslator type; 
}; 

} // namespace property_tree 
} // namespace boost 

int main() 
{ 
    boost::property_tree::iptree pt; 

    read_json("test.json", pt); 
    int i = pt.get<int>("number"); 
    int b = pt.get<bool>("enabled"); 
    std::cout << "i=" << i << " b=" << b << "\n"; 
} 

test.json:

{ 
    "number" : 42, 
    "enabled" : "Yes" 
} 

आउटपुट:

i=42 b=1 

कृपया ध्यान दें इस उदाहरण मानता है कि यह है कि संपत्ति पेड़ मामले असंवेदनशील है और std::string उपयोग करता है। यदि आप BoolTranslator अधिक सामान्य होने के लिए चाहते हैं, तो आपको BoolTranslator एक टेम्पलेट बनाना होगा और विस्तृत तारों और केस संवेदनशील तुलनाओं के लिए विशेषज्ञता प्रदान करना होगा।

+0

ठीक है, वाह। धन्यवाद @ एमिइल - यह काम करता है। यह वर्तमान में जादू से अलग है। मैंने अभी तक आउटपुट की कोशिश नहीं की है, लेकिन ऐसा लगता है कि 'झूठी' आउटपुट केवल मौके से काम करता है; झूठ के चारों ओर उद्धरण नहीं होना चाहिए? – Arunas

+0

हाहा, और निश्चित रूप से जब से मैं कोड के लिए बूस्ट टेस्ट केस लिख रहा हूं, यह भी स्पष्ट है कि 'str == "0" 'iquals (str," yes ")' – Arunas

+1

के समान वाक्य में नहीं है @ अरुणस: हां "झूठी" के आसपास उद्धरण होना चाहिए। मुझे आश्चर्य है कि संकलित भी। यदि आप * आंशिक टेम्पलेट विशेषज्ञता * का अध्ययन करने के लिए चारों ओर मिलता है, तो यह उत्तर इतना जादुई दिखाई नहीं देगा। :-) –

1

theboostcpplibraries.com पर भी एक अच्छा उदाहरण है।

उस आधार पर, मैं एक कस्टम पार्सर (घोषणा छोड़े गए) के लिए लिखा है:

boost::optional<bool> string_to_bool_translator::get_value(const std::string &s) { 
    auto tmp = boost::to_lower_copy(s); 
    if (tmp == "true" || tmp == "1" || tmp == "y" || tmp == "on") { 
     return boost::make_optional(true); 
    } else if (tmp == "false" || tmp == "0" || tmp == "n" || tmp == "off") { 
     return boost::make_optional(false); 
    } else { 
     return boost::none; 
    } 
} 

यह केवल bool और std :: स्ट्रिंग लेकिन आसानी से बढ़ाई के लिए है।

फिर,

boost::property_tree::ptree pt; 
... 
string_to_bool_translator tr; 
auto optional_value = pt.get_optional<bool>(key, tr); 
+0

जो कि @ f4 में सुझाया गया है पहले के जवाब की टिप्पणियां। एक पूर्ण उदाहरण के लिए +1। ध्यान दें कि चूंकि आपको अनुवादक निर्दिष्ट करना है, इसलिए यह ऐसी चीज है जो किसी के द्वारा भुलाए जाने की संभावना है और इससे भ्रम पैदा हो सकता है। – Arunas

+0

सच है। मुझे लगता है कि अनुवादक_बेटवीन क्या सुनिश्चित करेगा, लेकिन मैंने इसे अनदेखा किया और अभी तक इसे आजमाया नहीं है। – sebkraemer