सिंगल या डबल कोट्स से घिरे न होने पर स्पेस का उपयोग करके स्ट्रिंग को विभाजित करने के लिए रेगेक्स


114

मैं नियमित अभिव्यक्ति के लिए नया हूं और आपकी मदद की सराहना करूंगा। मैं एक साथ एक अभिव्यक्ति डालने की कोशिश कर रहा हूं, जो सभी रिक्त स्थान का उपयोग करके उदाहरण स्ट्रिंग को विभाजित करेगा जो एकल या दोहरे उद्धरणों से घिरे नहीं हैं। मेरा आखिरी प्रयास इस तरह दिखता है: (?!")और काफी काम नहीं कर रहा है। यह बोली से पहले अंतरिक्ष में बंट रहा है।

उदाहरण इनपुट:

This is a string that "will be" highlighted when your 'regular expression' matches something.

वांछित उत्पादन:

This
is
a
string
that
will be
highlighted
when
your
regular expression
matches
something.

ध्यान दें "will be"और 'regular expression'शब्दों के बीच के स्थान को बनाए रखें।


क्या आप वास्तव में "स्प्लिट" विधि का उपयोग कर रहे हैं, या मिलानकर्ता पर "खोज" विधि के साथ लूपिंग पर्याप्त होगा?
इरिकसन

9
"और अब उन्हें दो समस्याएं हैं"

जवाबों:


251

मुझे समझ में नहीं आता कि अन्य सभी ऐसे जटिल नियमित अभिव्यक्ति या इतने लंबे कोड का प्रस्ताव क्यों दे रहे हैं। अनिवार्य रूप से, आप दो प्रकार की चीजों को अपने स्ट्रिंग से हथियाना चाहते हैं: पात्रों के अनुक्रम जो रिक्त स्थान या उद्धरण नहीं हैं, और उन पात्रों के अनुक्रम जो एक उद्धरण के साथ शुरू और अंत होते हैं, बीच में कोई उद्धरण नहीं, दो प्रकार के उद्धरणों के लिए। आप इस नियमित अभिव्यक्ति के साथ उन चीजों को आसानी से मिला सकते हैं:

[^\s"']+|"([^"]*)"|'([^']*)'

मैंने कैप्चरिंग समूहों को जोड़ा क्योंकि आप सूची में उद्धरण नहीं चाहते हैं।

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

List<String> matchList = new ArrayList<String>();
Pattern regex = Pattern.compile("[^\\s\"']+|\"([^\"]*)\"|'([^']*)'");
Matcher regexMatcher = regex.matcher(subjectString);
while (regexMatcher.find()) {
    if (regexMatcher.group(1) != null) {
        // Add double-quoted string without the quotes
        matchList.add(regexMatcher.group(1));
    } else if (regexMatcher.group(2) != null) {
        // Add single-quoted string without the quotes
        matchList.add(regexMatcher.group(2));
    } else {
        // Add unquoted word
        matchList.add(regexMatcher.group());
    }
} 

यदि आपको दी गई सूची में उद्धरण होने से कोई आपत्ति नहीं है, तो आप बहुत सरल कोड का उपयोग कर सकते हैं:

List<String> matchList = new ArrayList<String>();
Pattern regex = Pattern.compile("[^\\s\"']+|\"[^\"]*\"|'[^']*'");
Matcher regexMatcher = regex.matcher(subjectString);
while (regexMatcher.find()) {
    matchList.add(regexMatcher.group());
} 

1
जनवरी, आपकी प्रतिक्रिया के लिए धन्यवाद। BTW, मैं एडिटपैड का बहुत बड़ा प्रशंसक हूं।
carlsz

क्या होगा अगर मैं तार में बच गए उद्धरणों को अनुमति देना चाहता हूं \"?
मॉन्स्टरूर

3
इस उत्तर के साथ समस्या बेमिसाल उद्धरण के साथ है: John's motherपरिणाम में [John, s, mother]
विभाजित

2
इस समस्या को ठीक करने के लिए, आप ऑपरेंड्स को थोड़ा-थोड़ा करके री-ऑर्डर कर सकते हैं और व्हाट्सएप-ग्रुप के कोट्स को छोड़ सकते हैं "([^"]*)"|'([^']*)'|[^\s]+:।
भूत

1
इस और अन्य उत्तरों के आधार पर, निम्नलिखित रेगेक्स उद्धरणों के अंदर पात्रों से बचने की अनुमति देता है "([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|[^\s]+:। देखें stackoverflow.com/questions/5695240/…
Limnic

15

StackOverflow पर कई प्रश्न हैं जो नियमित अभिव्यक्तियों का उपयोग करते हुए विभिन्न संदर्भों में इसी प्रश्न को कवर करते हैं। उदाहरण के लिए:

अद्यतन : एकल और डबल उद्धृत स्ट्रिंग को संभालने के लिए नमूना regex। रेफरी: मैं उद्धरण के अलावा किसी तार पर कैसे विभाजित हो सकता हूं?

m/('.*?'|".*?"|\S+)/g 

एक त्वरित पर्ल स्निपेट के साथ इसका परीक्षण किया गया और आउटपुट नीचे पुन: पेश किया गया। खाली स्ट्रिंग्स या व्हॉट्सएप-केवल स्ट्रिंग्स के लिए काम करता है यदि वे उद्धरणों के बीच हैं (निश्चित नहीं है कि यह वांछित है या नहीं)।

This
is
a
string
that
"will be"
highlighted
when
your
'regular expression'
matches
something.

ध्यान दें कि इसमें मिलान किए गए मानों में स्वयं उद्धरण वर्ण शामिल हैं, हालांकि आप इसे स्ट्रिंग को प्रतिस्थापित करने के साथ हटा सकते हैं, या उन्हें शामिल न करने के लिए regex को संशोधित कर सकते हैं। मैं पाठक या अब के लिए एक और पोस्टर के लिए एक अभ्यास के रूप में छोड़ता हूँ, क्योंकि 2am रास्ता नियमित रूप से और अब के साथ खिलवाड़ होने की देर है;)


मुझे लगता है कि आपका रेगेक्स बेमेल उद्धरणों की अनुमति देता है, जैसे "होगा" और 'नियमित अभिव्यक्ति'।
ज़च स्क्रिपवेना

@Zach - आप सही हैं, यह करता है ... इसे ठीक करने के लिए इसे अपडेट किया गया है
Jay

6

यदि आप स्ट्रिंग के अंदर बच गए उद्धरणों को अनुमति देना चाहते हैं, तो आप कुछ इस तरह का उपयोग कर सकते हैं:

(?:(['"])(.*?)(?<!\\)(?>\\\\)*\1|([^\s]+))

कोट किए गए तार समूह 2 होंगे, एकल अयोग्य शब्द समूह 3 होंगे।

आप इसे विभिन्न तार पर यहाँ आज़मा सकते हैं: http://www.fileformat.info/tool/regex.htm या http://gskinner.com/RegExr/


3

Jan Goyvaerts से रेगेक्स मुझे अब तक मिला सबसे अच्छा समाधान है, लेकिन खाली (अशक्त) मेल भी बनाता है, जिसे वह अपने कार्यक्रम में शामिल नहीं करता है। ये खाली मैच रेगेक्स टेस्टर (जैसे rubular.com) से भी दिखाई देते हैं। यदि आप खोजों को घेर लेते हैं (पहले उद्धृत भागों और अंतरिक्ष से अलग शब्दों के लिए देखें) तो आप इसे एक बार में कर सकते हैं:

("[^"]*"|'[^']*'|[\S]+)+

2
(?<!\G".{0,99999})\s|(?<=\G".{0,99999}")\s

यह रिक्त स्थान को दोहरे उद्धरण चिह्नों से घिरा नहीं होगा। मुझे मिनट, अधिकतम {0,99999} का उपयोग करना होगा, क्योंकि जावा * * और + को तलाश में समर्थन नहीं करता है।


1

संभवतः प्रत्येक भाग को हथियाने, बनाम इसे विभाजित करने के लिए स्ट्रिंग को खोजना आसान होगा।

कारण, आप इसे पहले और बाद के स्थानों पर विभाजित कर सकते हैं "will be"। लेकिन, मैं किसी विभाजन के बीच के स्थान को अनदेखा करने का कोई तरीका नहीं सोच सकता।

(वास्तविक जावा नहीं)

string = "This is a string that \"will be\" highlighted when your 'regular expression' matches something.";

regex = "\"(\\\"|(?!\\\").)+\"|[^ ]+"; // search for a quoted or non-spaced group
final = new Array();

while (string.length > 0) {
    string = string.trim();
    if (Regex(regex).test(string)) {
        final.push(Regex(regex).match(string)[0]);
        string = string.replace(regex, ""); // progress to next "word"
    }
}

इसके अलावा, एकल उद्धरणों को कैप्चर करने से समस्याएं हो सकती हैं:

"Foo's Bar 'n Grill"

//=>

"Foo"
"s Bar "
"n"
"Grill"

आपका समाधान एकल-उद्धृत स्ट्रिंग्स को संभालता नहीं है, जो कार्ल के उदाहरण का हिस्सा हैं।
जन गोयवर्ट्स

1

String.split()यहाँ मददगार नहीं है क्योंकि उद्धरणों (विभाजन नहीं) और बाहर के (विभाजन) के भीतर रिक्त स्थान के बीच अंतर करने का कोई तरीका नहीं है। Matcher.lookingAt()शायद वही है जो आपको चाहिए:

String str = "This is a string that \"will be\" highlighted when your 'regular expression' matches something.";
str = str + " "; // add trailing space
int len = str.length();
Matcher m = Pattern.compile("((\"[^\"]+?\")|('[^']+?')|([^\\s]+?))\\s++").matcher(str);

for (int i = 0; i < len; i++)
{
    m.region(i, len);

    if (m.lookingAt())
    {
        String s = m.group(1);

        if ((s.startsWith("\"") && s.endsWith("\"")) ||
            (s.startsWith("'") && s.endsWith("'")))
        {
            s = s.substring(1, s.length() - 1);
        }

        System.out.println(i + ": \"" + s + "\"");
        i += (m.group(0).length() - 1);
    }
}

जो निम्नलिखित उत्पादन का उत्पादन करता है:

0: "This"
5: "is"
8: "a"
10: "string"
17: "that"
22: "will be"
32: "highlighted"
44: "when"
49: "your"
54: "regular expression"
75: "matches"
83: "something."

1

मुझे माक्र्स का दृष्टिकोण पसंद आया, हालांकि, मैंने इसे संशोधित किया ताकि मैं उद्धरणों के पास पाठ की अनुमति दे सकूं, और दोनों "और" उद्धरण वर्णों का समर्थन कर सकूं। उदाहरण के लिए, मुझे [a = "में विभाजित न करने के लिए" a = "कुछ मान" की आवश्यकता थी। कुछ मूल्य "]।

(?<!\\G\\S{0,99999}[\"'].{0,99999})\\s|(?<=\\G\\S{0,99999}\".{0,99999}\"\\S{0,99999})\\s|(?<=\\G\\S{0,99999}'.{0,99999}'\\S{0,99999})\\s"

1

जन का दृष्टिकोण बहुत अच्छा है लेकिन यहाँ रिकॉर्ड के लिए एक और एक है।

शीर्षक में उल्लेख किया है के रूप में आप वास्तव में विभाजित करना चाहता था, तो में उद्धरण रखने "will be"और 'regular expression', तो आप इस विधि जिनमें से सीधे बाहर है इस्तेमाल कर सकते हैं मैच एक पैटर्न S1, S2, S3 आदि परिस्थितियों के अलावा (या प्रतिस्थापित करें)

रेगेक्स:

'[^']*'|\"[^\"]*\"|( )

दो बायाँ विकल्प पूर्ण 'quoted strings'और मेल खाते हैं "double-quoted strings"। हम इन मैचों की अनदेखी करेंगे। दाईं ओर समूह 1 के लिए रिक्त स्थान से मेल खाता है, और हम जानते हैं कि वे सही स्थान हैं क्योंकि वे बाईं ओर के भावों से मेल नहीं खाते थे। हम उन लोगों को बदल देते हैं जिनके SplitHereबाद विभाजन होता है SplitHere। फिर, यह एक सच्चे विभाजन के मामले के लिए है जहाँ आप चाहते हैं "will be", नहीं will be

यहां पूर्ण कार्य कार्यान्वयन है ( ऑनलाइन डेमो पर परिणाम देखें )।

import java.util.*;
import java.io.*;
import java.util.regex.*;
import java.util.List;

class Program {
public static void main (String[] args) throws java.lang.Exception  {

String subject = "This is a string that \"will be\" highlighted when your 'regular expression' matches something.";
Pattern regex = Pattern.compile("\'[^']*'|\"[^\"]*\"|( )");
Matcher m = regex.matcher(subject);
StringBuffer b= new StringBuffer();
while (m.find()) {
    if(m.group(1) != null) m.appendReplacement(b, "SplitHere");
    else m.appendReplacement(b, m.group(0));
}
m.appendTail(b);
String replaced = b.toString();
String[] splits = replaced.split("SplitHere");
for (String split : splits) System.out.println(split);
} // end main
} // end Program

1

यदि आप c # का उपयोग कर रहे हैं, तो आप उपयोग कर सकते हैं

string input= "This is a string that \"will be\" highlighted when your 'regular expression' matches <something random>";

List<string> list1 = 
                Regex.Matches(input, @"(?<match>\w+)|\""(?<match>[\w\s]*)""|'(?<match>[\w\s]*)'|<(?<match>[\w\s]*)>").Cast<Match>().Select(m => m.Groups["match"].Value).ToList();

foreach(var v in list1)
   Console.WriteLine(v);

मैंने विशेष रूप से " | <<(? [\ W \ s] *)> " को हाइलाइट करने के लिए कहा है कि आप किसी भी वर्ण को समूह वाक्यांशों में निर्दिष्ट कर सकते हैं। (इस मामले में मैं समूह में <> का उपयोग कर रहा हूं ।

आउटपुट है:

This
is
a
string
that
will be
highlighted
when
your
regular expression 
matches
something random

0

मैं निश्चित रूप से निश्चित हूं कि अकेले नियमित भावों का उपयोग करना संभव नहीं है। यह जाँचना कि क्या कुछ अन्य टैग के अंदर निहित है, एक पार्सिंग ऑपरेशन है। यह एक ही समस्या की तरह लगता है जैसे एक्सएमएल को रेक्स के साथ पार्स करने की कोशिश करना - यह सही तरीके से नहीं किया जा सकता है। आप एक गैर-लालची, गैर-वैश्विक regex को बार-बार लागू करके अपने वांछित परिणाम प्राप्त करने में सक्षम हो सकते हैं, जो उद्धृत तारों से मेल खाता है, फिर एक बार जब आप कुछ और नहीं पा सकते हैं, तो इसे रिक्त स्थान पर विभाजित करें ... जिसमें कई नंबर हों सभी सबस्ट्रिंग्स के मूल क्रम पर नज़र रखने सहित समस्याएं। आपका सबसे अच्छा शर्त सिर्फ एक बहुत ही सरल फ़ंक्शन लिखना है जो स्ट्रिंग पर पुनरावृत्त करता है और आपके द्वारा इच्छित टोकन को बाहर निकालता है।


यह एक रेगेक्स के साथ संभव है, कुछ नमूने देखें जिन्हें मैंने जोड़ा था। इस पर कुछ भिन्नताएँ हैं, और मैंने SO पर कई समान प्रश्न देखे हैं जो इसे नियमित अभिव्यक्तियों के माध्यम से संबोधित करते हैं।
Jay

1
पता है कि जब regex का उपयोग नहीं करना अधिक सहायक ज्ञान है, तो (? ([''] ((। *?)? (<!!!) (?! \ _ \\) * * 1 ([? ^ \ _] +))
रेने

0

जनवरी के स्वीकृत उत्तर पर एक दंपत्ति को उम्मीद है कि मददगार होगा:

(['"])((?:\\\1|.)+?)\1|([^\s"']+)
  • उद्धृत स्ट्रिंग्स के भीतर बच गए उद्धरणों की अनुमति देता है
  • एकल और दोहरे उद्धरण के लिए पैटर्न को दोहराने से बचा जाता है; जरूरत पड़ने पर (अधिक एक कैप्चरिंग ग्रुप के खर्च पर) अधिक उद्धरण चिह्नों को जोड़ना सरल करता है

यह उन में एपोस्ट्रोफ के साथ शब्दों को तोड़ता है, जैसेyou're
एड्रियन

0

आप यह भी आज़मा सकते हैं:

    String str = "This is a string that \"will be\" highlighted when your 'regular expression' matches something";
    String ss[] = str.split("\"|\'");
    for (int i = 0; i < ss.length; i++) {
        if ((i % 2) == 0) {//even
            String[] part1 = ss[i].split(" ");
            for (String pp1 : part1) {
                System.out.println("" + pp1);
            }
        } else {//odd
            System.out.println("" + ss[i]);
        }
    }

आपको वास्तव में कुछ स्पष्टीकरण जोड़ना चाहिए कि यह क्यों काम करना चाहिए - आप कोड के साथ-साथ कोड में टिप्पणियों को भी जोड़ सकते हैं - अपने वर्तमान रूप में, यह कोई स्पष्टीकरण प्रदान नहीं करता है जो बाकी समुदाय को समझने में मदद कर सकता है कि क्या आपने प्रश्न को हल / उत्तर देने के लिए किया था। यह उन सवालों के लिए विशेष रूप से महत्वपूर्ण है जिनके पास पहले से ही उत्तर हैं।
ishmelMakitla

0

निम्नलिखित तर्कों की एक सरणी देता है। तर्क रिक्त स्थान पर परिवर्तनशील 'कमांड' विभाजन हैं, जब तक कि एकल या दोहरे उद्धरण चिह्नों में शामिल न हों। फिर एकल और दोहरे उद्धरण चिह्नों को हटाने के लिए मैचों को संशोधित किया जाता है।

using System.Text.RegularExpressions;

var args = Regex.Matches(command, "[^\\s\"']+|\"([^\"]*)\"|'([^']*)'").Cast<Match>
().Select(iMatch => iMatch.Value.Replace("\"", "").Replace("'", "")).ToArray();

2
क्या आप अपने उत्तर में थोड़ा सा स्पष्टीकरण जोड़ सकते हैं ताकि अन्य इसे आसानी से समझ सकें? आदर्श रूप से हम कोड-केवल उत्तरों से बचना चाहते हैं।
जाकज

0

String.split () का उपयोग करके पहला वन-लाइनर

String s = "This is a string that \"will be\" highlighted when your 'regular expression' matches something.";
String[] split = s.split( "(?<!(\"|').{0,255}) | (?!.*\\1.*)" );

[This, is, a, string, that, "will be", highlighted, when, your, 'regular expression', matches, something.]

रिक्त पर विभाजित न करें, यदि रिक्त रिक्त एकल या डबल उद्धरण से घिरा हुआ है
, जब 255 वर्ण बाईं ओर और रिक्त के दाईं ओर सभी वर्ण न तो एकल और न ही दोहरे उद्धरण

मूल पोस्ट से अनुकूलित (केवल दोहरे उद्धरण हैंडल)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.