2010-08-12 16 views
6

मेरे पास एक वैध क्लोजर फ़ॉर्म वाला एक स्ट्रिंग है। मैं इसके एक हिस्से को प्रतिस्थापित करना चाहता हूं, बस assoc-in के साथ, लेकिन पूरे स्ट्रिंग को टोकन के रूप में संसाधित करना चाहता हूं।सिंटेक्स-जागरूक सबस्ट्रिंग प्रतिस्थापन

=> (assoc-in [:a [:b :c]] [1 0] :new) 
[:a [:new :c]] 
=> (assoc-in [:a 
       [:b,, :c]] [1 0] :new) 
[:a [:new :c]] 
=> (string-assoc-in "[:a 
         [:b,, :c]]" [1 0] ":new") 
"[:a 
    [:new,, :c]]" 

मैं string-assoc-in लिखना चाहता हूं। ध्यान दें कि इसके पहले और अंतिम तर्क तार हैं, और यह लाइन ब्रेक और कॉमा रखता है। क्या यह क्लोजर में किया जा सकता है? मुझे मिली सबसे नज़दीकी चीज़ read है जो clojure.lang.LispReader पर कॉल करती है, लेकिन मुझे नहीं पता कि कैसे काम करता है।

मैं इसे क्लोजर स्रोत फ़ाइल पढ़ने के लिए उपयोग करना चाहता हूं और फ़ाइल की संरचना को बनाए रखने के साथ इसे कुछ संशोधनों के साथ प्रदर्शित करना चाहता हूं।

+2

मैं अपने स्वयं के पाठक को लिखने के बिना इस भरोसेमंद तरीके से ऐसा करने के किसी भी तरीके से नहीं सोच सकता। –

+0

* मुझे * –

+0

@ पॉल नाथन के लिए डिफैमक्रो की तरह लगता है: असल में एक लिस्प मैक्रो के पास नियमित कार्य के रूप में एक ही स्ट्रिंग-मैनिपुलेशन ऑपरेशन होता है। पौलुस ग्राहम ने इसे "पूरी भाषा हमेशा वहां" दी। :-) –

उत्तर

2

मुझे लगता है यह, काम करना चाहिए पूरी तरह से सामान्य हो सकता है और अपने स्वयं के रीडर/पार्सर की आवश्यकता नहीं:

(defn is-clojure-whitespace? [c] 
    (or (Character/isSpace c) 
     (= \, c))) 

(defn whitespace-split 
    "Returns a map of true -> (maximal contiguous substrings of s 
    consisting of Clojure whitespace), false -> (as above, non-whitespace), 
    :starts-on-whitespace? -> (whether s starts on whitespace)." 
    [s] 
    (if (empty? s) 
    {} 
    (assoc (group-by (comp is-clojure-whitespace? first) 
        (map (partial apply str) 
          (partition-by is-clojure-whitespace? s))) 
     :starts-on-whitespace? 
     (if (is-clojure-whitespace? (first s)) true false)))) 

(defn string-assoc-in [s coords subst] 
    (let [{space-blocks true 
     starts-on-whitespace? :starts-on-whitespace?} 
     (whitespace-split s) 
     s-obj (assoc-in (binding [*read-eval* false] (read-string s)) 
         coords 
         (binding [*read-eval* false] (read-string subst))) 
     {non-space-blocks false} 
     (whitespace-split (pr-str s-obj))] 
    (apply str 
      (if starts-on-whitespace? 
      (interleave space-blocks (concat non-space-blocks [nil])) 
      (interleave non-space-blocks (concat space-blocks [nil])))))) 

उदाहरण:

user> (string-assoc-in "[:a [:b,, :c]]" [1 0] ":new") 
"[:a [:new,, :c]]" 

अद्यतन:

: आउच, एक बग पकड़ा
user> (string-assoc-in "[:a [:b,, :c\n]]" [1 0] ":new") 
"[:a [:new,, :c]]\n" 

अगर इससे कोई फर्क नहीं पड़ता तो मुझे इससे अच्छा लगेगा, लेकिन मुझे लगता है कि मैं हवल ई इसके बारे में कुछ करने और करने के लिए ... sigh

+0

मुझे इस चाल को व्हाइटस्पेस पर विभाजित करने के साथ पसंद है, फिर फिर से अंतःक्रिया करना। यह मुझे एक तरीका है कि पाठक लिखने के बिना ऐसा कैसे करें। –

+0

मैं एक पाठक लिखना नहीं चाहता था। विडंबना यह है कि, आपके उत्तर के बारे में सोचने से मुझे एक लिखने का मौका मिला है। –

1

मुझे लगता है कि आप वास्तव में एक रूप में पढ़ना नहीं चाहते हैं और इसका मूल्यांकन करना चाहते हैं? fnparse में Clojure parser है (Fnparse का उपयोग करके क्लोजर में लिखा गया है)। आप स्ट्रिंग से फ़ॉर्म में लाने के लिए इसका उपयोग करने में सक्षम हो सकते हैं, फिर हेरफेर कर सकते हैं, फिर उसे स्ट्रिंग पर वापस रख दें?

(defn string-assoc-in 
    [a b c] 
    (.replaceAll 
    (str 
    (assoc-in (read-string (.replaceAll a ",," ",_,")) b (read-string c))) 
    " _ " ",, ")) 

user> (string-assoc-in "[:a [:b,, :c]]" [1 0] ":new") 
"[:a [:new,, :c]]" 

ध्यान दें कि हम एक आरक्षित प्लेसहोल्डर चरित्र की आवश्यकता होती है (इस मामले में, _) जो आप नहीं चाहते हैं:

2

आप (पठन-स्ट्रिंग) और कुछ स्ट्रिंग परिवर्तन के संयोजन के साथ ऐसा कर सकता है अपने खोजशब्दों में ये चाल उन लोगों को प्राप्त करने के लिए है, जब पाठक वेक्टर स्ट्रिंग पर क्रंच कर रहा है, फिर उन्हें वापस रखें।

यह नमूना न्यूलाइन को संबोधित नहीं करता है, लेकिन मुझे लगता है कि आप उन्हें उसी तरह से संभाल सकते हैं।

+0

मैं अनुवर्ती नहीं हूं - '(चलो [एस "[: एक [: बी, सी]]"] (स्ट्रिंग-assoc-in s [1 0] ": नया"))' ठीक काम करता है? हालांकि, मैं सहमत हूं कि मैक्रो अनावश्यक है और यह कि एक समारोह भी काम करेगा (मैक्रो समाधान के साथ मेरे खराब होने से एक आर्टिफैक्ट था), इसलिए मैं defn का उपयोग करने के लिए उत्तर संपादित कर दूंगा। – Greg

+1

@all: ग्रेग एक टिप्पणी का जवाब दे रहा है जिसमें मैंने गलती से दावा किया कि उपर्युक्त काम नहीं करेगा। मैं इसे एक संशोधित संस्करण के साथ प्रतिस्थापित करने जा रहा था - थोड़ी देर की टिप्पणी पोस्ट करके और मूल को हटाकर - लेकिन, एक सुंदर गलती में, मैंने हटाएं * पहले * पर क्लिक किया। क्षमा करें, कुछ मिनट के लिए टिप्पणी के बाद जाने का तरीका नहीं है। * श्वास * @ ग्रेग: आप सही हैं, किसी भी दर पर, भ्रम के लिए खेद है। –

+1

मुझे अपने समाधान के लिए विचार देने के लिए इसे एक से ऊपर रखा गया, हालांकि अब मैं देखता हूं कि यह मेरे कोड में खोजे जाने के बाद से वही/बहुत ही समान बग प्रदर्शित करता है (उदाहरण के लिए प्रयास करें '(स्ट्रिंग-assoc-in "[: a [: बी,: सी,]] "[1 0]": नया ")' या '[: बी,]' या '[: बी, सी]' ...)। ऐसा लगता है कि इस के लिए एक पार्सर/विशेष उद्देश्य पाठक से परहेज नहीं है। –

4

या कोई अन्य विकल्प ANTLRparse the Clojure कोड को एएसटी में उपयोग करना होगा, फिर एएसटी को बदलना होगा, और एक स्ट्रिंग पर वापस निर्यात करना होगा।

+0

आह, यह सबसे अच्छा तरीका हो सकता है ... सीसीडब्ल्यू का व्याकरण व्यापक और अच्छी तरह से बनाए रखा जा सकता है (और समय के साथ उस तरह रहने के लिए!)। हालांकि, मेरे छिपे हुए चैनल पर रखी गई सामग्री को निकालने के तरीके के बारे में जानने के लिए मेरे एएनटीएलआर-फू अभी भी बहुत कमजोर हैं। मैंने सोचा कि लेक्सर इसे देखता है, लेकिन पार्सर नहीं करता है ...? –

+0

मुझे नहीं पता था कि एएनटीएलआर के लिए क्लोजर व्याकरण फ़ाइल है, सूचक के लिए धन्यवाद। हालांकि, मैं शुद्ध क्लोजर समाधान पसंद करूंगा। –

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