जावा में स्ट्रिंग प्रतिस्थापन, एक वेग टेम्पलेट के समान


96

क्या Stringजावा में कोई प्रतिस्थापन तंत्र है, जहां मैं एक पाठ के साथ वस्तुओं को पारित कर सकता हूं, और यह स्ट्रिंग को प्रतिस्थापित करता है जैसा कि होता है।
उदाहरण के लिए, पाठ है:

Hello ${user.name},
    Welcome to ${site.name}. 

मेरे पास जो वस्तुएं हैं "user"और हैं "site"। मैं ${}वस्तुओं से इसके समकक्ष मूल्यों के साथ अंदर दिए गए तारों को बदलना चाहता हूं । यह वैसा ही है जैसे हम वस्तुओं को एक वेग टेम्पलेट में बदलते हैं।


1
कहाँ बदलें? एक कक्षा? एक JSP? स्ट्रिंग में एक प्रारूप विधि है यदि आप बस:String.format("Hello %s", username);
Droo

1
@ डरो: उदाहरण में, स्ट्रिंग की तरह है Hello ${user.name}, जैसे नहीं, Hello %sया Hello {0}
अडेल अंसारी

2
यदि आपको कुछ ऐसा चाहिए जो वेग जैसा दिखता है और वेग की तरह गंध आती है, तो शायद यह वेग है? :)
सर्ग

@ ड्रू: इसकी क्लास नहीं। मैंने एक "स्ट्रिंग" चर में उपरोक्त पाठ दिया है और संबंधित वस्तुओं में मूल्यों के साथ $ {} के अंदर स्ट्रिंग की सभी घटनाओं को बदलना चाहता है। उदाहरण के लिए "उपयोगकर्ता" ऑब्जेक्ट में नाम संपत्ति के साथ सभी $ {user.name} को बदलें।
जो

@serg: हाँ यह एक वेग कोड है। और मैं अपने कोड से वेग निकालना चाहता हूं।
जो

जवाबों:


142

StringSubstitutorअपाचे कॉमन्स टेक्स्ट से उपयोग करें ।

https://commons.apache.org/proper/commons-text/

यह आप (और इसके खुले स्रोत के लिए ...)

 Map<String, String> valuesMap = new HashMap<String, String>();
 valuesMap.put("animal", "quick brown fox");
 valuesMap.put("target", "lazy dog");
 String templateString = "The ${animal} jumped over the ${target}.";
 StringSubstitutor sub = new StringSubstitutor(valuesMap);
 String resolvedString = sub.replace(templateString);

4
StrSubstitutor के लिए जावाडोक commons.apache.org/lang/api-release/org/apache/commons/lang/...
पॉल

1
होना चाहिए Map<String, String> valuesMap = new HashMap<String, String>();
andrrjones

3
StrSubstitutorअब https://commons.apache.org/proper/commons-lang/ में पदावनत किया गया है । उपयोगकर्ता https://commons.apache.org/proper/commons-text/ इसके बजाय
लुकुलुबा

7
StrSubstitutor1.3 के रूप में पदावनत, StringSubstitutorइसके बजाय उपयोग करें । 2.0 में यह क्लास हटा दी जाएगी। आयात के लिए ग्रेड निर्भरता StringSubstitutorहैorg.apache.commons:commons-text:1.4
यूरी राबेशको

क्या यह स्थिति आधारित प्रतिस्थापन की अनुमति देता है?
गौरव

130

java.text.MessageFormatक्लास पर एक नज़र डालें , MessageFormat ऑब्जेक्ट का एक सेट लेता है, उन्हें प्रारूपित करता है, फिर उपयुक्त स्थानों पर पैटर्न में स्वरूपित स्ट्रिंग्स सम्मिलित करता है।

Object[] params = new Object[]{"hello", "!"};
String msg = MessageFormat.format("{0} world {1}", params);

10
धन्यवाद! मुझे पता था कि जावा में एक इनबिल्ट तरीका होना चाहिए बिना उपयोग किए बिना इस तरह के एक साधारण काम करने के लिए टेम्पलेट इंजन को फ्रिक कर रहे हैं!
जोसेफ राजीव मोथा


6
+1। जागरूक रहें, formatएक Object...वैरिएग भी लेते हैं ताकि आप इस अधिक format("{0} world {1}", "Hello", "!");
ट्रिक

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

22

मेरा पसंदीदा तरीका है, String.format()क्योंकि इसके एक oneliner और तीसरे पक्ष के पुस्तकालयों की आवश्यकता नहीं है:

String message = String.format("Hello! My name is %s, I'm %s.", name, age); 

मैं इसे नियमित रूप से उपयोग करता हूं, जैसे अपवाद संदेशों में:

throw new Exception(String.format("Unable to login with email: %s", email));

संकेत: आप जितने चाहें उतने वेरिएबल्स में डाल सकते हैं क्योंकि Varargsformat() का उपयोग करता है


यह कम उपयोगी है जब आपको एक ही तर्क को एक से अधिक बार दोहराने की आवश्यकता होती है। उदाहरण के लिए: String.format("Hello! My name is %s, I'm %s. Why is my name %s you ask? Well I'm only %s years old so I don't know", name, age, name, age);। यहां अन्य उत्तरों को केवल एक बार प्रत्येक तर्क को निर्दिष्ट करने की आवश्यकता है।
आशेरबार

2
@asherbar आप प्रारूप स्ट्रिंग में तर्क सूचकांक विनिर्देशक का उपयोग कर सकते हैं, जैसेString.format("Hello! My name is %1$s, I'm %2$s. Why is my name %1$s you ask? Well I'm only %2$s years old so I don't know", name, age)
jazzpi

@jazzpi मुझे कभी नहीं पता था। धन्यवाद!
अशरबार

20

मैंने इसके एक छोटे परीक्षण कार्यान्वयन को एक साथ फेंक दिया। मूल विचार formatप्रारूप स्ट्रिंग, और वस्तुओं का एक नक्शा, और उन नामों को कॉल और पास करना है जो उनके पास स्थानीय स्तर पर हैं।

निम्नलिखित का आउटपुट है:

मेरे कुत्ते का नाम फिदो है, और जेन डो उसका मालिक है।

public class StringFormatter {

    private static final String fieldStart = "\\$\\{";
    private static final String fieldEnd = "\\}";

    private static final String regex = fieldStart + "([^}]+)" + fieldEnd;
    private static final Pattern pattern = Pattern.compile(regex);

    public static String format(String format, Map<String, Object> objects) {
        Matcher m = pattern.matcher(format);
        String result = format;
        while (m.find()) {
            String[] found = m.group(1).split("\\.");
            Object o = objects.get(found[0]);
            Field f = o.getClass().getField(found[1]);
            String newVal = f.get(o).toString();
            result = result.replaceFirst(regex, newVal);
        }
        return result;
    }

    static class Dog {
        public String name;
        public String owner;
        public String gender;
    }

    public static void main(String[] args) {
        Dog d = new Dog();
        d.name = "fido";
        d.owner = "Jane Doe";
        d.gender = "him";
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("d", d);
        System.out.println(
           StringFormatter.format(
                "My dog is named ${d.name}, and ${d.owner} owns ${d.gender}.", 
                map));
    }
}

नोट: यह बिना किसी अपवाद के संकलन नहीं है। लेकिन यह कोड को पढ़ने में बहुत आसान बनाता है।

इसके अलावा, मुझे यह पसंद नहीं है कि आपको कोड में खुद ही नक्शे का निर्माण करना होगा, लेकिन मुझे नहीं पता कि स्थानीय रूप से स्थानीय चर के नाम कैसे प्राप्त करें। इसे करने का सबसे अच्छा तरीका यह है कि जैसे ही आप इसे बनाएं, ऑब्जेक्ट को मैप में रखना याद रखें।

निम्न उदाहरण उन परिणामों का उत्पादन करता है जो आप अपने उदाहरण से चाहते हैं:

public static void main(String[] args) {
    Map<String, Object> map = new HashMap<String, Object>();
    Site site = new Site();
    map.put("site", site);
    site.name = "StackOverflow.com";
    User user = new User();
    map.put("user", user);
    user.name = "jjnguy";
    System.out.println(
         format("Hello ${user.name},\n\tWelcome to ${site.name}. ", map));
}

मुझे यह भी उल्लेख करना चाहिए कि मुझे पता नहीं है कि वेग क्या है, इसलिए मुझे आशा है कि यह उत्तर प्रासंगिक है।


यह वही है जिसे मैं देख रहा था। कार्यान्वयन देने के लिए धन्यवाद। मैं इसके लिए प्रयास कर रहा था और गलत परिणाम प्राप्त कर रहा था। : डी। वैसे भी इससे मेरी समस्या हल हो गई।
जो

2
@ जो, खुशी है कि मैं मदद कर सकता था। जावा में प्रतिबिंब का उपयोग करने वाले कुछ कोड को लिखने का अभ्यास करना आखिरकार मेरे लिए एक अच्छा बहाना था।
jjnguy

6

यहां बताया गया है कि आप इसे कैसे कर सकते हैं। इसे वास्तविक कोड के रूप में लागू करने के लिए अपेक्षाकृत सरल होना चाहिए।

  1. सभी ऑब्जेक्ट्स का एक मैप बनाएं, जिसे टेम्प्लेट में संदर्भित किया जाएगा।
  2. टेम्पलेट में परिवर्तनशील संदर्भ खोजने के लिए एक नियमित अभिव्यक्ति का उपयोग करें और उन्हें अपने मूल्यों के साथ बदलें (चरण 3 देखें)। Matcher वर्ग उपयोगी हो पाते हैं और बदलें के लिए होगा।
  3. डॉट पर चर नाम विभाजित करें। user.nameबन जाएगा userऔर nameuserऑब्जेक्ट प्राप्त करने के लिए अपने मानचित्र में देखें और ऑब्जेक्ट से मूल्य प्राप्त करने के लिए प्रतिबिंब का उपयोग करें name। मान लें कि आपकी वस्तुओं में मानक गेटर्स हैं, आप एक विधि की तलाश करेंगे getNameऔर इसे लागू करेंगे।

हे, बस इस जवाब को देखा। यह मेरे लिए समान है। कृपया मुझे बताएं कि आप मेरे कार्यान्वयन के बारे में क्या सोचते हैं।
jjnguy

5

वहाँ वहाँ बाहर अभिव्यक्ति भाषा कार्यान्वयन के एक जोड़े है कि आप के लिए यह करता है, के रूप में या अगर अपने requirments बढ़ने अपने स्वयं के कार्यान्वयन का उपयोग करने के लिए बेहतर हो सकता है उदाहरण के लिए देखें हैं जुएल और MVEL

मुझे कम से कम एक परियोजना में एमवीईएल का सफलतापूर्वक उपयोग करना और पसंद है।

गैर JSP (स्टैंडअलोन) संदर्भ में स्टैकफ़्लो पोस्ट JSTL / JSP EL (अभिव्यक्ति भाषा) देखें


0

बॉक्स के बाहर कुछ भी नहीं है जो वेग के बराबर है क्योंकि वेग को उस समस्या को हल करने के लिए लिखा गया था। निकटतम चीज़ जो आप आज़मा सकते हैं, वह फ़ॉर्मैटर में दिख रही है

http://cupi2.uniandes.edu.co/site/images/recursos/javadoc/j2se/1.5.0/docs/api/java/util/Formatter.html

हालाँकि, जहाँ तक मुझे पता है कि फ़ॉर्मेट सी को जावा में फ़ॉर्मेटिंग विकल्पों की तरह प्रदान करने के लिए बनाया गया था, तो हो सकता है कि यह आपकी खुजली को ठीक से खरोंच न करे लेकिन आपका स्वागत है :)।


0

मैं GroovyShell का उपयोग जावा में Groovy GString के साथ टेम्पलेट पार्स करने के लिए करता हूं:

Binding binding = new Binding();
GroovyShell gs = new GroovyShell(binding);
// this JSONObject can also be replaced by any Java Object
JSONObject obj = new JSONObject();
obj.put("key", "value");
binding.setProperty("obj", obj)
String str = "${obj.key}";
String exp = String.format("\"%s\".toString()", str);
String res = (String) gs.evaluate(exp);
// value
System.out.println(str);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.