मैं जावा में CamelCase को मानव-पठनीय नामों में कैसे बदलूं?


157

मैं एक ऐसी विधि लिखना चाहता हूं जो CamelCase को मानव-पठनीय नाम में परिवर्तित करती है।

यहाँ परीक्षण मामला है:

public void testSplitCamelCase() {
    assertEquals("lowercase", splitCamelCase("lowercase"));
    assertEquals("Class", splitCamelCase("Class"));
    assertEquals("My Class", splitCamelCase("MyClass"));
    assertEquals("HTML", splitCamelCase("HTML"));
    assertEquals("PDF Loader", splitCamelCase("PDFLoader"));
    assertEquals("A String", splitCamelCase("AString"));
    assertEquals("Simple XML Parser", splitCamelCase("SimpleXMLParser"));
    assertEquals("GL 11 Version", splitCamelCase("GL11Version"));
}

5
सबसे पहले, आपको रूपांतरण के नियमों को निर्दिष्ट करने की आवश्यकता होगी। उदाहरण के लिए, कैसे PDFLoaderबनता है PDF Loader?
जॉर्न शॉ-रोड

2
मैं उस प्रारूप को "PascalCase" कहता हूं। "कैमलकेज़" में पहला अक्षर लोअरकेस होना चाहिए। कम से कम जहां तक ​​डेवलपर्स का संबंध है। msdn.microsoft.com/en-us/library/x2dbyw72(v=vs.71).aspx
Muhd

जवाबों:


337

यह आपके परीक्षण के साथ काम करता है:

static String splitCamelCase(String s) {
   return s.replaceAll(
      String.format("%s|%s|%s",
         "(?<=[A-Z])(?=[A-Z][a-z])",
         "(?<=[^A-Z])(?=[A-Z])",
         "(?<=[A-Za-z])(?=[^A-Za-z])"
      ),
      " "
   );
}

यहाँ एक परीक्षण हार्नेस है:

    String[] tests = {
        "lowercase",        // [lowercase]
        "Class",            // [Class]
        "MyClass",          // [My Class]
        "HTML",             // [HTML]
        "PDFLoader",        // [PDF Loader]
        "AString",          // [A String]
        "SimpleXMLParser",  // [Simple XML Parser]
        "GL11Version",      // [GL 11 Version]
        "99Bottles",        // [99 Bottles]
        "May5",             // [May 5]
        "BFG9000",          // [BFG 9000]
    };
    for (String test : tests) {
        System.out.println("[" + splitCamelCase(test) + "]");
    }

यह रिक्त स्थान के साथ शून्य लंबाई मिलान रेगेक्स का उपयोग करता है और जहां रिक्त स्थान सम्मिलित करने के लिए आकर्षक दिखता है। मूल रूप से 3 पैटर्न हैं, और मैं String.formatइसे और अधिक पठनीय बनाने के लिए उन्हें एक साथ रखने के लिए उपयोग करता हूं ।

तीन पैटर्न हैं:

मेरे पीछे यूसी, यूसी मेरे पीछे एलसी और उसके बाद एलसी

  XMLParser   AString    PDFLoader
    /\        /\           /\

मेरे पीछे गैर-यूसी, मेरे सामने यूसी

 MyClass   99Bottles
  /\        /\

मेरे पीछे पत्र, मेरे सामने गैर-पत्र

 GL11    May5    BFG9000
  /\       /\      /\

संदर्भ

संबंधित सवाल

विभाजित करने के लिए शून्य-लंबाई मिलान लुकर का उपयोग करना:


1
अवधारणा सी # के रूप में अच्छी तरह से (एक ही नियमित अभिव्यक्ति के साथ, लेकिन थोड़ा अलग-अलग नियमित-अभिव्यक्ति रूपरेखा, निश्चित रूप से) काम करती है। उत्कृष्ट कार्य। धन्यवाद!
गम

लगता है कि पायथन पर मेरे लिए काम नहीं कर रहा है, यह हो सकता है क्योंकि रेगेक्स इंजन समान नहीं है। मुझे कुछ कम सुरुचिपूर्ण करने की कोशिश करनी होगी, मुझे डर है। :)
मारियोविलास

2
क्या कोई समझा सकता है कि% s |% s |% s का मतलब टेस्टीसेस के संबंध में है और आम तौर पर भी?
Ari53nN3o

1
@ Ari53nN3o: " %s"String.format(String format, args...) तर्क के लिए प्लेसहोल्डर हैं । आप सूचकांक द्वारा भी कॉल कर सकते हैं:String.format("%$1s|%$2s|%$3s", ...
श्री पॉलीविरल

यह c # में कैसे काम करेगा? relaceAllअगर स्ट्रिंग में " ." है, तो भी कोई विभाजन नहीं जोड़ना चाहता ।
सरोजानंद

119

आप इसका उपयोग कर सकते हैं org.apache.commons.lang.StringUtils

StringUtils.join(
     StringUtils.splitByCharacterTypeCamelCase("ExampleTest"),
     ' '
);

9
यह समाधान सबसे ऊपर चढ़े हुए से बेहतर है क्योंकि: ए) यह पहिया का फिर से आविष्कार नहीं करता है: कॉमन्स-लैंग एक डी-फैक्टो मानक है और यह ठीक काम करता है, प्रदर्शन पर बहुत ध्यान केंद्रित करता है। b) जब रूपांतरण बहुत बार किया जाता है, तो यह विधि regex- आधारित एक की तुलना में बहुत तेज़ होती है: यह 100,000 बार पूर्वोक्त परीक्षण निष्पादित करने के लिए मेरा बेंचमार्क है: `` regex- आधारित विधि 4820 मिलीसेकंड लिया ///// ///// कॉमन्स-लैंग-बेस्ड मेथड में 232 मिलीसेकंड लिया गया `` `जो कि रेक्स का उपयोग करने वाले की तुलना में लगभग 20 गुना तेज है !!!!
क्लिंट ईस्टवुड

2
मैं निश्चित रूप से इस पर क्लिंट से सहमत हूं, यह स्वीकृत उत्तर होना चाहिए। प्रदर्शन एक चीज है, लेकिन युद्ध-परीक्षण वाले पुस्तकालय का उपयोग करना निश्चित रूप से एक अच्छा प्रोग्रामिंग अभ्यास है।
जूलियन

1
या जावा 8 के String.join () विधि: String.join ("", StringUtils.splitByCharacterTypeCamelCase ("ExampleTest") का उपयोग करके;
dk7

आप क्लिंट ईस्टवुड से कैसे सहमत नहीं हो सकते हैं? :)
डेनिजेला

19

साफ और छोटा समाधान:

StringUtils.capitalize(StringUtils.join(StringUtils.splitByCharacterTypeCamelCase("yourCamelCaseText"), StringUtils.SPACE)); // Your Camel Case Text

जैसा कि पहले assertप्रश्न में दिखाया गया है , पूंजीकरण वांछित नहीं है।
slartidan

बग को पकड़ने के लिए धन्यवाद, उत्तर को अपडेट करेगा।
साहिल छाबड़ा

10

यदि आपको "जटिल" रेगेक्स पसंद नहीं है, और दक्षता के बारे में बिल्कुल परेशान नहीं हैं, तो मैंने तीन चरणों में समान प्रभाव को प्राप्त करने के लिए इस उदाहरण का उपयोग किया है।

String name = 
    camelName.replaceAll("([A-Z][a-z]+)", " $1") // Words beginning with UC
             .replaceAll("([A-Z][A-Z]+)", " $1") // "Words" of only UC
             .replaceAll("([^A-Za-z ]+)", " $1") // "Words" of non-letters
             .trim();

यह ऊपर दिए गए सभी परीक्षण मामलों को पास करता है, जिनमें अंक वाले भी शामिल हैं।

जैसा कि मैं कहता हूं, यह कुछ अन्य उदाहरणों में एक नियमित अभिव्यक्ति का उपयोग करने के रूप में अच्छा नहीं है - लेकिन कोई इसे अच्छी तरह से उपयोगी पा सकता है।


1
धन्यवाद, यह बहुत अच्छा था। मैंने एक जावास्क्रिप्ट संस्करण बनाया ।
श्री पॉलीविरल

यदि आप एक regex लाइब्रेरी / टूल के साथ काम कर रहे हैं, तो यह एकमात्र तरीका है, जो lookbehind / lookforward (जैसे golang का regexp पैकेज) का समर्थन नहीं करता है। अच्छा काम।
mdwhatcott

6

आप org.modeshape.common.text.Inflector का उपयोग कर सकते हैं

विशेष रूप से:

String humanize(String lowerCaseAndUnderscoredWords,
    String... removableTokens) 

पहले शब्द को कैपिटल करता है और "_id" और किसी भी रिमूवेबल टोकन को ट्रेस करते हुए स्पेस और स्ट्रिप्स में अंडरस्कोर करता है।

मावेन विरूपण साक्ष्य है: org.modeshape: modhape-common: 2.3.0.Final

JBoss भंडार पर: https://repository.jboss.org/nexus/content/repositories/relits

यहाँ JAR फ़ाइल है: https://repository.jboss.org/nexus/content/repositories/releases/org/modeshape/modeshape-common/2.3.0.Final/modeshape-common-2.3.0.Final.jar


1

निम्नलिखित रेगेक्स का उपयोग शब्दों के अंदर की राजधानियों की पहचान करने के लिए किया जा सकता है:

"((?<=[a-z0-9])[A-Z]|(?<=[a-zA-Z])[0-9]]|(?<=[A-Z])[A-Z](?=[a-z]))"

यह प्रत्येक कैपिटल लेटर से मेल खाता है, जो कि एक गैर-कैपिटल लेटर या अंक के बाद या उसके बाद एक कम केस लेटर और एक लेटर के बाद हर अंक से मेल खाता है।

उनके जावा स्पेस से पहले एक स्पेस कैसे डालें =)

अंक मामले और पीडीएफ लोडर मामले को शामिल करने के लिए संपादित।


@ यानिवे: मैंने सिर्फ अंक देखे हैं ... इससे चीजें और जटिल हो सकती हैं। संभवत: उन्हें पकड़ने का एक और रेगेक्स आसान तरीका होगा।
जेन्स

@Jens: यह से मेल खाएगी Lमें PDFLoader?
जॉर्न शॉ-रोड

कैसे (? <= [a-z0-9]) [A-Z0-9]?
यानिवे

3
अब, मैं आपके रेगेक्स कौशल की बहुत प्रशंसा करता हूं, लेकिन मुझे इसे बनाए रखने के लिए नफरत होगी।
क्रिस नाइट

1
@ क्रिस: हाँ, यह सच है। रेगेक्स केवल लिखने वाली भाषा का अधिक है। =) हालांकि यह विशेष अभिव्यक्ति पढ़ने के लिए बहुत कठिन नहीं है, अगर आप |"या" के रूप में पढ़ते हैं । खैर ... शायद यह है ... मैं बदतर देखा है / /
Jens

1

मुझे लगता है कि आपको स्ट्रिंग पर चलना होगा और लोअरकेस से अपरकेस, अपरकेस से लेकर लोअरकेस, अल्फाबेटिक टू न्यूमेरिक, न्यूमेरिकल से लेकर अल्फाबेटिक तक के बदलावों का पता लगाना होगा। हर परिवर्तन पर आप एक अपवाद के साथ एक स्थान सम्मिलित करते हैं, हालांकि: ऊपरी से निचले हिस्से में एक स्थान पर आप पहले एक वर्ण डालें।


1

यह .NET में काम करता है ... अपनी पसंद के अनुसार अनुकूलित करें। मैंने टिप्पणियां जोड़ीं ताकि आप समझ सकें कि प्रत्येक टुकड़ा क्या कर रहा है। (RegEx को समझना मुश्किल हो सकता है)

public static string SplitCamelCase(string str)
{
    str = Regex.Replace(str, @"([A-Z])([A-Z][a-z])", "$1 $2");  // Capital followed by capital AND a lowercase.
    str = Regex.Replace(str, @"([a-z])([A-Z])", "$1 $2"); // Lowercase followed by a capital.
    str = Regex.Replace(str, @"(\D)(\d)", "$1 $2"); //Letter followed by a number.
    str = Regex.Replace(str, @"(\d)(\D)", "$1 $2"); // Number followed by letter.
    return str;
}

0

रिकॉर्ड के लिए, यहां लगभग (*) संगत स्काला संस्करण है:

  object Str { def unapplySeq(s: String): Option[Seq[Char]] = Some(s) }

  def splitCamelCase(str: String) =
    String.valueOf(
      (str + "A" * 2) sliding (3) flatMap {
        case Str(a, b, c) =>
          (a.isUpper, b.isUpper, c.isUpper) match {
            case (true, false, _) => " " + a
            case (false, true, true) => a + " "
            case _ => String.valueOf(a)
          }
      } toArray
    ).trim

एक बार संकलित करने के बाद इसे जावा से सीधे उपयोग किया जा सकता है यदि संबंधित स्कैल्प-लाइब्रेरी.जर क्लासपथ में है।

(*) यह उस इनपुट के "GL11Version"लिए विफल हो जाता है जिसके लिए वह वापस लौटता है "G L11 Version"


0

मैंने रेगेक्स को पॉलीजेन लुब्रिकेंट से लिया और इसे वस्तुओं पर एक विस्तार विधि में बदल दिया:

    /// <summary>
    /// Turns a given object into a sentence by:
    /// Converting the given object into a <see cref="string"/>.
    /// Adding spaces before each capital letter except for the first letter of the string representation of the given object.
    /// Makes the entire string lower case except for the first word and any acronyms.
    /// </summary>
    /// <param name="original">The object to turn into a proper sentence.</param>
    /// <returns>A string representation of the original object that reads like a real sentence.</returns>
    public static string ToProperSentence(this object original)
    {
        Regex addSpacesAtCapitalLettersRegEx = new Regex(@"(?<=[A-Z])(?=[A-Z][a-z]) | (?<=[^A-Z])(?=[A-Z]) | (?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace);
        string[] words = addSpacesAtCapitalLettersRegEx.Split(original.ToString());
        if (words.Length > 1)
        {
            List<string> wordsList = new List<string> { words[0] };
            wordsList.AddRange(words.Skip(1).Select(word => word.Equals(word.ToUpper()) ? word : word.ToLower()));
            words = wordsList.ToArray();
        }
        return string.Join(" ", words);
    }

यह सब कुछ एक पठनीय वाक्य में बदल जाता है। यह पारित वस्तु पर एक ToString करता है। फिर यह स्ट्रिंग को विभाजित करने के लिए पॉलीजेनिल लुब्रिकेंट्स द्वारा दिए गए रेगेक्स का उपयोग करता है। तब यह प्रत्येक शब्द को पहले शब्द और किसी भी समादेश के लिए छोड़ देता है। सोचा कि यह किसी के लिए उपयोगी हो सकता है।


-2

मैं एक रेगेक्स निंजा नहीं हूं, इसलिए मैं स्ट्रिंग पर पुनरावृति करूंगा, वर्तमान स्थिति की सूचियों को जांचते हुए और पिछली स्थिति को ध्यान में रखते हुए। यदि वर्तमान स्थिति एक बड़ा अक्षर है, तो मैं पिछली स्थिति के बाद एक स्थान सम्मिलित करूँगा और प्रत्येक सूचकांक में वृद्धि करूँगा।


2
Psssh! उसमे मज़ा कहाँ है?
vbullinger

-3

http://code.google.com/p/inflection-js/

आप String.underscore ()। humanize () मेथड्स को CamelCase स्ट्रिंग ले सकते हैं और इसे मानव पठनीय स्ट्रिंग में बदल सकते हैं।


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