2016-01-20 11 views
5

साथ optparse-अनुप्रयोगी विकल्प मैं optparse-applicative उपयोग कर रहा हूँ और मैं इस तरह के रूप आदेश पंक्ति तर्क पार्स करने के लिए सक्षम होने के लिए करना चाहते हैं:से अधिक मान

$ ./program -a file1 file2 -b filea fileb 

यानी, दो स्विच, जो दोनों के कई तर्क ले जा सकते हैं ।

data MyOptions = MyOptions { 
    aFiles :: [String] 
    , bFiles :: [String] } 

और फिर एक Parser इस तरह::

तो मैं जो इस तरह दिखता है मेरे विकल्प के लिए एक डेटा प्रकार है

config :: Parser MyOptions 
config = MyOptions 
     <$> option (str >>= parseStringList) 
      (short 'a' <> long "aFiles") 
     <*> option (str >>= parseStringList) 
      (short 'b' <> long "bFiles") 

parseStringList :: Monad m => String -> m [String] 
parseStringList = return . words 

यह दृष्टिकोण में विफल रहता है यह अपेक्षित परिणाम दे देंगे कि जब प्रत्येक स्विच के लिए केवल एक तर्क प्रदान किया जाता है, लेकिन यदि आप दूसरा तर्क देते हैं तो आपको उस दूसरे तर्क के लिए "अवैध तर्क" मिलता है।

मुझे आश्चर्य हुआ कि क्या मैं यह दिखाकर इसे रोक सकता हूं कि मैं चार विकल्प चाहता था: एक बूलियन स्विच (यानी -a); तारों की एक सूची; एक और बुलियन स्विच (यानी -b); और तारों की एक और सूची। तो मैं अपने डेटा प्रकार परिवर्तित:

data MyOptions = MyOptions { 
    isA :: Bool 
    , aFiles :: [String] 
    , isB :: Bool 
    , bFiles :: [String] } 

और फिर इस तरह पार्सर संशोधित:

config :: Parser MyOptions 
config = MyOptions 
     <$> switch 
      (short 'a' <> long "aFiles") 
     <*> many (argument str (metavar "FILE")) 
     <*> switch 
      (short 'b' <> long "bFiles") 
     <*> many (argument str (metavar "FILE")) 

इस बार के बजाय एक स्ट्रिंग सूची के लिए एक स्पष्ट पार्सर many और argument combinators का उपयोग कर।

लेकिन अब पहले many (argument str (metavar "FILE"))सभी तर्कों की, -b स्विच निम्नलिखित उन सहित खपत करता है।

तो मैं इस तर्क पार्सर को कैसे लिख सकता हूं?

उत्तर

4

आदेशों के अलावा, optparse-applicativegetopts सम्मेलन का पालन करता है: कमांड लाइन पर एक भी तर्क एक विकल्प तर्क तर्क से मेल खाता है। यह, यहां तक ​​कि थोड़ा और अधिक सख्त है, क्योंकि getopts ही स्विच के साथ एक से अधिक विकल्प की अनुमति देगा:

./program-with-getopts -i input1 -i input2 -i input3 

तो वहाँ कोई "जादू" आप तुरंत तरह

./program-with-magic -a 1 2 3 -b foo bar crux 

के बाद से अपने प्रोग्राम का उपयोग करने में मदद कर सकते है Options.Applicative.Parser इस बात को ध्यान में नहीं लिखा गया था; यह POSIX conventions के विपरीत भी है, जहां विकल्प या तो एक तर्क या कोई नहीं लेते हैं।

हालांकि, अगर आप दोनों पक्षों से इस समस्या से निपटने कर सकते हैं: या तो getopts में, -a कई बार का उपयोग करें, जैसे आप, या उद्धरण चिह्नों का उपयोग करने के लिए उपयोगकर्ता बता:

./program-as-above -a "1 2 3" -b "foo bar crux" 
# works already with your program! 

एक विकल्प के कई उपयोग सक्षम करने के आपको many (यदि वे वैकल्पिक हैं) या some (यदि वे नहीं हैं) का उपयोग करना है।,

multiString desc = concat <$> some single 
    where single = option (str >>= parseStringList) desc 

config :: Parser MyOptions 
config = MyOptions 
    <$> multiString (short 'a' <> long "aFiles" <> help "Use quotes/multiple") 
    <*> multiString (short 'b' <> long "bFiles" <> help "Use quotes/multiple") 

जो आप

./program-with-posix-style -a 1 -a "2 3" -b foo -b "foo bar" 

का उपयोग लेकिन किसी भी पार्स करने पुस्तकालय मुझे पता करके अपने प्रस्तावित शैली समर्थित नहीं है के लिए सक्षम बनाता के बाद से मुक्त तर्कों की स्थिति अस्पष्ट होगा: तुम भी दोनों वेरिएंट को जोड़ सकते हैं । यदि आप वास्तव में -a 1 2 3 -b foo bar crux का उपयोग करना चाहते हैं, तो आपको तर्कों को स्वयं पार्स करना होगा।

+0

नि: शुल्क तर्क अस्पष्ट नहीं होंगे यदि '-a 'के तर्कों को' -' से शुरू नहीं किया गया था, हालांकि। – rampion

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