2015-06-03 8 views
5

मुझे गंदे डिज़ाइन के कारण किसी समस्या के साथ सौदा करना पड़ा। मुझे स्ट्रिंग की एक सूची मिलती है और इसमें से विशेषताओं को पार्स करना चाहते हैं। दुर्भाग्य से, मैं स्रोत नहीं बदल सकता, जहां ये स्ट्रिंग बनाए गए थे।स्ट्रिंग के गुणों को निकालें

उदाहरण:

String s = "type=INFO, languageCode=EN-GB, url=http://www.stackoverflow.com, ref=1, info=Text, that may contain all kind of chars., deactivated=false" 

अब मैं गुण type, languageCode, url, ref, info और deactivated निकालना चाहते हैं।

यहां समस्या info है, जिसका टेक्स्ट उद्धरण चिह्न से सीमित नहीं है। इस क्षेत्र में कॉमा भी हो सकता है, इसलिए यह पता लगाने के लिए कि स्ट्रिंग के अंत में कॉमा का उपयोग नहीं किया जा सकता है।

अतिरिक्त, उन तारों में हमेशा सभी विशेषताओं को शामिल नहीं किया जाता है। type, info और deactivated हमेशा मौजूद हैं, शेष वैकल्पिक है।

कोई सुझाव मैं इस समस्या को कैसे हल कर सकता हूं?

+0

इस तत्वों का क्रम तय है? – Pshemo

+1

'=' के लिए खोज करने के बारे में और उसके बाद एक शब्द को फ़ील्ड नाम के रूप में चुनें। '=' के बाद सबकुछ अगले फ़ील्ड नाम तक मूल्य है। यह मानता है कि मान में '=' ​​नहीं हो सकता है - यदि यह हो सकता है, तो आपके पास जाने के लिए बहुत कुछ नहीं है। – xxbbcc

+2

यदि सभी _other_ विशेषताओं में कुछ हद तक अनुमानित प्रारूप है, तो आप उन्हें हटा सकते हैं और 'जानकारी' के लिए जो कुछ भी बचे हैं ... –

उत्तर

2

मानते हुए तत्वों की है कि आदेश तय हो गई है तो आप इस एक

String s = "type=INFO, languageCode=EN-GB, url=http://www.stackoverflow.com, ref=1, info=Text, that may contain all kind of chars., deactivated=false"; 

String regex = //type, info and deactivated are always present 
      "type=(?<type>.*?)" 
     + "(?:, languageCode=(?<languageCode>.*?))?"//optional group 
     + "(?:, url=(?<url>.*?))?"//optional group 
     + "(?:, ref=(?<rel>.*?))?"//optional group 
     + ", info=(?<info>.*?)" 
     + ", deactivated=(?<deactivated>.*?)"; 
Pattern p = Pattern.compile(regex); 
Matcher m = p.matcher(s); 
if(m.matches()){ 
    System.out.println("type -> "+m.group("type")); 
    System.out.println("languageCode -> "+m.group("languageCode")); 
    System.out.println("url -> "+m.group("url")); 
    System.out.println("rel -> "+m.group("rel")); 
    System.out.println("info -> "+m.group("info")); 
    System.out.println("deactivated -> "+m.group("deactivated")); 
} 

आउटपुट की तरह regex का उपयोग कर समाधान लिख सकते हैं:

type -> INFO 
languageCode -> EN-GB 
url -> http://www.stackoverflow.com 
rel -> 1 
info -> Text, that may contain all kind of chars. 
deactivated -> false 

संपादित करें: Version2 regex oneOfPossibleKeys=value जहां value के लिए खोज समाप्त होता है:

  • , oneOfPossibleKeys=
  • या बाद यह ($ द्वारा प्रतिनिधित्व) स्ट्रिंग के अंत है।

कोड:

String s = "type=INFO, languageCode=EN-GB, url=http://www.stackoverflow.com, ref=1, info=Text, that may contain all kind of chars., deactivated=false"; 

String[] possibleKeys = {"type","languageCode","url","ref","info","deactivated"}; 
String keysStrRegex = String.join("|", possibleKeys); 
//above will contain type|languageCode|url|ref|info|deactivated 

String regex = "(?<key>\\b(?:"+keysStrRegex+")\\b)=(?<value>.*?(?=, (?:"+keysStrRegex+")=|$))"; 
    // (?<key>\b(?:type|languageCode|url|ref|info|deactivated)\b) 
    // = 
    // (?<value>.*?(?=, (?:type|languageCode|url|ref|info|deactivated)=|$))System.out.println(regex); 

Pattern p = Pattern.compile(regex); 
Matcher m = p.matcher(s); 


while(m.find()){ 
    System.out.println(m.group("key")+" -> "+m.group("value")); 
} 

आउटपुट:

type -> INFO 
languageCode -> EN-GB 
url -> http://www.stackoverflow.com 
ref -> 1 
info -> Text, that may contain all kind of chars. 
deactivated -> false 
+0

मेरे पास आपके संस्करण 2 जैसा ही विचार था। लेकिन आप वास्तविक कुंजी के लिए अपने 'keysStrRegex' का उपयोग क्यों नहीं कर रहे हैं, साथ ही, यानी '\\ w +' के बजाय? –

+0

@tobias_k यह एक बहुत अच्छा सवाल है। उत्तर अपडेट किया गया। – Pshemo

4

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

यह मानता है कि मान में = नहीं हो सकता है।

संपादित करें:

एक संभव तरीके के रूप में एम्बेडेड = को संभालने के लिए, आप देख सकते हैं अगर यह के सामने शब्द एक अपने ज्ञात फ़ील्ड नाम है - अगर नहीं, तो आप संभवतः एक एम्बेडेड के रूप में = इलाज कर सकते हैं ऑपरेटर की बजाय चरित्र। हालांकि, यह मानता है कि आपके पास ज्ञात फ़ील्ड का एक निश्चित सेट है (जिनमें से कुछ हमेशा प्रकट नहीं हो सकते हैं)। यदि आप जानते हैं कि फ़ील्ड नाम केस-संवेदी हैं तो यह धारणा आसान हो सकती है।

+2

"यह मानता है कि मान में' = 'नहीं हो सकता है, हमें ऐसी मजबूत धारणा की आवश्यकता नहीं है। हम यह भी मान सकते हैं कि '=' जो 'key = value' में विभाजक है, केवल शब्दों के विशिष्ट सेट से पहले किया जा सकता है। यदि इसमें पहले से कोई पूर्वनिर्धारित कुंजी शब्द नहीं है, तो यह मूल्य का हिस्सा होना चाहिए। – Pshemo

+0

@ पश्मो हे, मैं बस इसे लिख रहा था - आपकी टिप्पणी के लिए धन्यवाद। :) – xxbbcc

1

आप सभी "निश्चित" समूहों को कैप्चर करते हुए और info के लिए जो कुछ भी बना रहे हैं, उसका नियमित अभिव्यक्ति का उपयोग कर सकते हैं। यह भी काम करना चाहिए यदि info भाग में , या = वर्ण शामिल हैं। यहां कुछ त्वरित उदाहरण दिया गया है (पायथन का उपयोग करके, लेकिन यह कोई समस्या नहीं होनी चाहिए ...)।

>>> p = r"(type=[A-Z]+), (languageCode=[-A-Z]+), (url=[^,]+), (ref=\d), (info=.+?), (deactivated=(?:true|false))" 
>>> s = "type=INFO, languageCode=EN-GB, url=http://www.stackoverflow.com, ref=1, info=Text, that may contain all kind of chars, even deactivated=true., deactivated=false" 
>>> re.search(p, s).groups() 
('type=INFO', 
'languageCode=EN-GB', 
'url=http://www.stackoverflow.com', 
'ref=1', 
'info=Text, that may contain all kind of chars, even deactivated=true.', 
'deactivated=false') 

उन तत्वों के किसी भी वैकल्पिक हैं, तो आप उन समूहों के बाद एक ? रखा, और अल्पविराम वैकल्पिक कर सकते हैं। अगर आदेश अलग हो सकता है, तो यह अधिक जटिल है। इस मामले में, एक बार में सब कुछ कैप्चर करने के लिए एक RegEx का उपयोग करने के बजाय, व्यक्तिगत गुणों को कैप्चर करने के लिए कई RegExes का उपयोग करें और फिर अगली विशेषता से मेल खाने से पहले स्ट्रिंग में '' के साथ प्रतिस्थापित करें) को हटा दें। अंत में, info से मेल खाते हैं।


आगे विचार पर, यह देखते हुए कि उन विशेषताओं किसी भी क्रम अभी सब कुछ किसी एक कीवर्ड से अगले करने के लिए फैले, इसके वास्तविक सामग्री की परवाह किए बिना, बहुत Pshemo के समाधान के लिए इसी तरह कब्जा करने के लिए, इसे और अधिक होनहार हो सकता है हो सकता है:

keys = "type|languageCode|url|ref|info|deactivated" 
p = r"({0})=(.+?)(?=\, (?:{0})=|$)".format(keys) 
matches = re.findall(p, s) 

लेकिन यह भी कुछ अस्पष्ट मामलों में विफल हो सकता है, उदाहरण के लिए यदि info विशेषता में कॉमा सहित ', ref=foo' जैसे कुछ शामिल हैं। हालांकि, उन अस्पष्टताओं के आसपास कोई रास्ता नहीं लगता है। यदि आपके पास info=in this string, ref=1, and in another, ref=2, ref=1 जैसी स्ट्रिंग थी, तो इसमें ref विशेषता, या तीन, या कोई भी नहीं है?

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