স্ট্রিং ফর্ম্যাটে নামকরণ করা স্থানধারক


175

পাইথনে, স্ট্রিং ফর্ম্যাট করার সময়, আমি পজিশোল্ডারদের অবস্থানের পরিবর্তে নাম দ্বারা পূরণ করতে পারি:

print "There's an incorrect value '%(value)s' in column # %(column)d" % \
  { 'value': x, 'column': y }

আমি ভাবছি জাভাতে এটি সম্ভব কিনা (আশা করি, বাহ্যিক লাইব্রেরি ছাড়া)?


আপনি ম্যাসেজফর্ম্যাটটি প্রসারিত করতে পারেন এবং ভেরিয়েবল থেকে সূচকগুলিতে ম্যাপিং ফ্যাশনালিটি কার্যকর করতে পারেন।
vpram86


1
কিছু ইতিহাস: জাভা বেশিরভাগ ক্ষেত্রে সি / সি ++ অনুলিপি করে কারণ এটি সি ++ বিশ্ব থেকে বিকাশকারীদের আকৃষ্ট করার চেষ্টা করেছিল যেখানে %sসাধারণ অনুশীলন ছিল। এন.ইউইকিপিডিয়া. org / উইকি / প্রিন্টফ_ফরম্যাট_ স্ট্রিং # হিস্টোরি আরও উল্লেখ করুন যে কিছু আইডিই এবং ফাইন্ডব্যাগগুলি স্বয়ংক্রিয়ভাবে% s এবং% d গণনাগুলি সনাক্ত করতে পারে তবে আমি এখনও নামযুক্ত ক্ষেত্রগুলিকে পছন্দ করব।
ক্রিস্টোফ রাউসি

উত্তর:


143

জাকার্তা কমন্স ল্যাংয়ের স্ট্র্যাবস্টিটিউটর এটি করার একটি হালকা ওজন উপায় হ'ল যদি আপনার মানগুলি ইতিমধ্যে সঠিকভাবে ফর্ম্যাট হয়।

http://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/text/StrSubstitutor.html

Map<String, String> values = new HashMap<String, String>();
values.put("value", x);
values.put("column", y);
StrSubstitutor sub = new StrSubstitutor(values, "%(", ")");
String result = sub.replace("There's an incorrect value '%(value)' in column # %(column)");

উপরের ফলাফলগুলি:

"কলাম # 2 এ একটি ভুল মান '1' রয়েছে"

মাভেন ব্যবহার করার সময় আপনি এই pom.xml এ নির্ভরতা যুক্ত করতে পারেন:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.4</version>
</dependency>

2
আমি এটি হতাশ করে দেখেছি যে কীগুলি পাওয়া না গেলে গ্রন্থাগারটি নিক্ষেপ করে না, তবে আপনি যদি ${arg}উপরের কাস্টমটির পরিবর্তে ডিফল্ট সিনট্যাক্স ( ) ব্যবহার করেন ( %(arg)) তবে রেজেক্সটি সংকলন করবে না, এটি পছন্দসই প্রভাব।
জন লেহম্যান

2
মানচিত্রটিতে কীটি উপস্থিত না থাকলে আপনি একটি কাস্টম ভেরিয়েবল রিসোলভার সেট করতে পারেন এবং একটি ব্যতিক্রম ছুঁড়ে ফেলতে পারেন।
Mene

7
পুরানো থ্রেড, তবে 3.6 হিসাবে, পাঠ্য প্যাকেজটি কমন্স-পাঠ্যের পক্ষে অবচয় করা হয়েছিল। commons.apache.org/proper/commons-text
জেফ ওয়াকার

74

বেশ নয়, তবে আপনি একাধিকবার একটি মান উল্লেখ করতে বার্তা ফর্ম্যাটটি ব্যবহার করতে পারেন :

MessageFormat.format("There's an incorrect value \"{0}\" in column # {1}", x, y);

উপরেরটি স্ট্রিং.ফর্ম্যাট () দিয়েও করা যেতে পারে, তবে আমি বার্তা ফর্ম্যাট সিনট্যাক্স ক্লিনারটি পেয়েছি যদি আপনার জটিল এক্সপ্রেশন তৈরি করতে হয় তবে আপনি স্ট্রিংয়ের মধ্যে কী কী অবজেক্ট রেখেছেন সে সম্পর্কে আপনার যত্ন নেওয়া দরকার না plus


আপনি কেন পারবেন না তা নিশ্চিত নন, স্ট্রিংয়ের অবস্থানটি গুরুত্বপূর্ণ নয়, কেবলমাত্র আর্গের তালিকার পজিশন, এটি এটি একটি নামকরণের সমস্যা তৈরি করে। আপনি কীগুলির নাম জানেন, যার অর্থ আপনি আর্গুমেন্টের তালিকার কোনও কীটির জন্য অবস্থান নির্ধারণ করতে পারেন। এখন থেকে মান হিসাবে 0 এবং কলাম 1 হিসাবে পরিচিত হবে: মেসেজিফরম্যাট.ফর্ম্যাট ("কলামে {" {0} \ "একটি ভুল মান আছে # {1}, মান হিসাবে {0 using ব্যবহার করা অনেক সমস্যার কারণ হতে পারে", মানচিত্র) .get ('value'), valueMap.get ('কলাম'));
গিলাডবু

1
একটি সূত্রের জন্য ধন্যবাদ, এটি আমাকে সহজ ফাংশন লিখতে সহায়তা করেছে যা আমি যা চাই ঠিক তা করতে (আমি এটি নীচে রেখেছি)।
অ্যান্ডি

1
সম্মত, সিনট্যাক্সটি অনেক পরিষ্কার er সংখ্যার মানগুলি ফর্ম্যাট করার ক্ষেত্রে খুব খারাপ বার্তা ফর্ম্যাটটি তার নিজের মন পেয়েছে।
কিস ডি কুটার

এবং মনে হচ্ছে একক উদ্ধৃতি দ্বারা বেষ্টিত স্থানধারীদের উপেক্ষা করুন।
কেস ডি কুটার

MessageFormatঅপেক্ষাকৃত বড়
জসন

32

সরল নামযুক্ত স্থানধারকের জন্য অ্যাপাচি কমন স্ট্রিংসস্টিউটরের আর একটি উদাহরণ ।

String template = "Welcome to {theWorld}. My name is {myName}.";

Map<String, String> values = new HashMap<>();
values.put("theWorld", "Stackoverflow");
values.put("myName", "Thanos");

String message = StringSubstitutor.replace(template, values, "{", "}");

System.out.println(message);

// Welcome to Stackoverflow. My name is Thanos.

আপনি যদি খুব বড় ফাইল লোড করার প্রত্যাশা করেন তবে আমি খুঁজে পেয়েছি এই লাইব্রেরিটি replaceInকোন বাফারে মানগুলি পরিবর্তিত করে: স্ট্রিংবিল্ডার বা টেক্সটস্ট্রিংবিল্ডারকে সমর্থন করে। এই পদ্ধতির সাথে, ফাইলের সম্পূর্ণ সামগ্রী মেমরিতে লোড হবে না।
এডওয়ার্ড করিগাল

15

আপনি স্ট্রিংটেম্পলেট লাইব্রেরি ব্যবহার করতে পারেন , এটি আপনার যা চান তা আরও অনেক কিছু সরবরাহ করে।

import org.antlr.stringtemplate.*;

final StringTemplate hello = new StringTemplate("Hello, $name$");
hello.setAttribute("name", "World");
System.out.println(hello.toString());

'unexpected char: '''
চরটি

11

জন্য খুব সহজ ক্ষেত্রে আপনি কেবল সেখানে একটি লাইব্রেরি জন্য কোন প্রয়োজন একটি হার্ডকোডেড স্ট্রিং প্রতিস্থাপন ব্যবহার করতে পারেন:

    String url = "There's an incorrect value '%(value)' in column # %(column)";
    url = url.replace("%(value)", x); // 1
    url = url.replace("%(column)", y); // 2

সতর্কতা : আমি কেবল সহজতম কোডটি দেখাতে চেয়েছিলাম। অবশ্যই এটি গুরুতর উত্পাদনের কোডের জন্য ব্যবহার করবেন না যেখানে সুরক্ষার বিষয়গুলি মন্তব্যগুলিতে বলা হয়েছে: পলায়ন, ত্রুটি পরিচালনা এবং সুরক্ষা এখানে একটি বিষয়। তবে সবচেয়ে খারাপ ক্ষেত্রে আপনি এখন জানেন যে 'ভাল' লাইব কেন ব্যবহার করা প্রয়োজন :-)


1
এটি একটি সহজ এবং সহজ, তবে খারাপ দিকটি হ'ল যখন মূল্যটি পাওয়া যায় নি তখন এটি নিঃশব্দে ব্যর্থ হয়। এটি কেবল প্লেসোল্ডারটিকে মূল স্ট্রিংয়ে রেখে দেয়।
kiedysktos

@ কিয়েডিসটকোস, আপনি একটি চেক করে এটির উন্নতি করতে পারেন, তবে আপনি যদি পুরো জিনিসটি চান, তবে একটি লিব ব্যবহার করুন :)
ক্রিস্টোফ রাউসি

2
সতর্কতা: যেহেতু এই কৌশলটি মধ্যবর্তী পরিবর্তনের ফলাফলগুলিকে তাদের নিজস্ব ফর্ম্যাট স্ট্রিং হিসাবে বিবেচনা করে, তাই এই সমাধানটি স্ট্রিং আক্রমণগুলিকে ফর্ম্যাট করার ক্ষেত্রে ঝুঁকিপূর্ণ । যে কোনও সঠিক সমাধান ফর্ম্যাট স্ট্রিংয়ের মাধ্যমে একটি একক পাস করা উচিত।
200_সাক্সেস

@ 200_সাক্সেস হ্যাঁ ভালো বিষয় সুরক্ষা সম্পর্কে কথা বলার জন্য অবশ্যই এই কোডটি গুরুতর উত্পাদন ব্যবহারের জন্য নয় ...
ক্রিস্টোফ রাউসি

8

সব আপনার সাহায্যের জন্য ধন্যবাদ! আপনার সমস্ত চিহ্ন ব্যবহার করে, আমি যা চাই তা করতে রুটিন লিখেছি - অভিধান ব্যবহার করে পাইথনের মতো স্ট্রিং বিন্যাস। যেহেতু আমি জাভা নবাগত, যে কোনও ইঙ্গিত প্রশংসা করা হয়।

public static String dictFormat(String format, Hashtable<String, Object> values) {
    StringBuilder convFormat = new StringBuilder(format);
    Enumeration<String> keys = values.keys();
    ArrayList valueList = new ArrayList();
    int currentPos = 1;
    while (keys.hasMoreElements()) {
        String key = keys.nextElement(),
        formatKey = "%(" + key + ")",
        formatPos = "%" + Integer.toString(currentPos) + "$";
        int index = -1;
        while ((index = convFormat.indexOf(formatKey, index)) != -1) {
            convFormat.replace(index, index + formatKey.length(), formatPos);
            index += formatPos.length();
        }
        valueList.add(values.get(key));
        ++currentPos;
    }
    return String.format(convFormat.toString(), valueList.toArray());
}

লোম্বোর জবাবের বিপরীতে, এটি অসীম লুপে আটকে formatPosথাকতে পারে না , কারণ এটি থাকতে পারে না formatKey
অ্যারন ডুফর

6
সতর্কতা: যেহেতু লুপটি মধ্যবর্তী প্রতিস্থাপনের ফলাফলগুলিকে তাদের নিজস্ব ফর্ম্যাট স্ট্রিং হিসাবে বিবেচনা করে, তাই এই সমাধানটি স্ট্রিং আক্রমণগুলিকে বিন্যাস করতে ঝুঁকিপূর্ণ । যে কোনও সঠিক সমাধান ফর্ম্যাট স্ট্রিংয়ের মাধ্যমে একটি একক পাস করা উচিত।
200_সাক্সেস

6

এটি একটি পুরানো থ্রেড তবে কেবল রেকর্ডের জন্য আপনি জাভা 8 স্টাইলটিও ব্যবহার করতে পারেন:

public static String replaceParams(Map<String, String> hashMap, String template) {
    return hashMap.entrySet().stream().reduce(template, (s, e) -> s.replace("%(" + e.getKey() + ")", e.getValue()),
            (s, s2) -> s);
}

ব্যবহার:

public static void main(String[] args) {
    final HashMap<String, String> hashMap = new HashMap<String, String>() {
        {
            put("foo", "foo1");
            put("bar", "bar1");
            put("car", "BMW");
            put("truck", "MAN");
        }
    };
    String res = replaceParams(hashMap, "This is '%(foo)' and '%(foo)', but also '%(bar)' '%(bar)' indeed.");
    System.out.println(res);
    System.out.println(replaceParams(hashMap, "This is '%(car)' and '%(foo)', but also '%(bar)' '%(bar)' indeed."));
    System.out.println(replaceParams(hashMap, "This is '%(car)' and '%(truck)', but also '%(foo)' '%(bar)' + '%(truck)' indeed."));
}

আউটপুটটি হবে:

This is 'foo1' and 'foo1', but also 'bar1' 'bar1' indeed.
This is 'BMW' and 'foo1', but also 'bar1' 'bar1' indeed.
This is 'BMW' and 'MAN', but also 'foo1' 'bar1' + 'MAN' indeed.

এটি উজ্জ্বল, তবে দুর্ভাগ্যক্রমে এটি এখানে চশমাগুলি লঙ্ঘন করে ডকস.অরাকল.com/javase/ 8/ docs/api/java/util/stream/… প্রথম প্যারামটি পরিচয় হলে কম্বিনার ফাংশনটি অবশ্যই দ্বিতীয় প্যারামিটারটি ফিরিয়ে আনতে হবে। উপরের একটি পরিবর্তে পরিচয়টি ফিরিয়ে দেবে। এটিও এই বিধি লঙ্ঘন করে: combiner.apply (u, accumulator.apply (পরিচয়, t)) == accumulator.apply (ইউ, টি)
আলী শেইতো

আকর্ষণীয় ... তবে আপনি যদি মানচিত্রটি পাস করার জন্য কোনও দুর্দান্ত উপায় প্রস্তাব করেন তবে সর্বাধিক ফর্ম্যাটিং কোডের মতো টেমপ্লেটের পরেও যদি সম্ভব হয়।
ক্রিস্টোফ রাউসি

4
সতর্কতা: যেহেতু .reduce()মধ্যবর্তী প্রতিস্থাপনের ফলাফলগুলি তাদের নিজস্ব ফর্ম্যাট স্ট্রিং হিসাবে আচরণ করে, তাই এই সমাধানটি স্ট্রিং আক্রমণগুলিকে ফর্ম্যাট করার ক্ষেত্রে ঝুঁকিপূর্ণ । যে কোনও সঠিক সমাধান ফর্ম্যাট স্ট্রিংয়ের মাধ্যমে একটি একক পাস করা উচিত।
200_সাক্সেস

6
public static String format(String format, Map<String, Object> values) {
    StringBuilder formatter = new StringBuilder(format);
    List<Object> valueList = new ArrayList<Object>();

    Matcher matcher = Pattern.compile("\\$\\{(\\w+)}").matcher(format);

    while (matcher.find()) {
        String key = matcher.group(1);

        String formatKey = String.format("${%s}", key);
        int index = formatter.indexOf(formatKey);

        if (index != -1) {
            formatter.replace(index, index + formatKey.length(), "%s");
            valueList.add(values.get(key));
        }
    }

    return String.format(formatter.toString(), valueList.toArray());
}

উদাহরণ:

String format = "My name is ${1}. ${0} ${1}.";

Map<String, Object> values = new HashMap<String, Object>();
values.put("0", "James");
values.put("1", "Bond");

System.out.println(format(format, values)); // My name is Bond. James Bond.

2
এটির উত্তরটি হওয়া উচিত, যেহেতু এটি ফর্ম্যাট স্ট্রিং আক্রমণগুলিকে এড়িয়ে চলে যা এখানে অন্যান্য সমাধানগুলির বেশিরভাগ ক্ষেত্রেই ঝুঁকিপূর্ণ। নোট করুন যে জাভা 9 .replaceAll()স্ট্রিং প্রতিস্থাপন কলব্যাক্সের সমর্থন সহ এটি আরও সহজ করে তুলেছে
200_সুকেস

এটি উত্তর হওয়া উচিত, এর জন্য এটি কোনও বাহ্যিক গ্রন্থাগার ব্যবহার করে না।
বোহাও এলআই

3

আমি একটি ছোট লাইব্রেরির লেখক যা আপনি যা চান ঠিক তা করে:

Student student = new Student("Andrei", 30, "Male");

String studStr = template("#{id}\tName: #{st.getName}, Age: #{st.getAge}, Gender: #{st.getGender}")
                    .arg("id", 10)
                    .arg("st", student)
                    .format();
System.out.println(studStr);

অথবা আপনি যুক্তিগুলি শৃঙ্খলাবদ্ধ করতে পারেন:

String result = template("#{x} + #{y} = #{z}")
                    .args("x", 5, "y", 10, "z", 15)
                    .format();
System.out.println(result);

// Output: "5 + 10 = 15"

আপনার লাইব্রেরির সাথে শর্ত ভিত্তিক বিন্যাস করা কি সম্ভব?
গৌরব

@ গৌরব বেশ নয় আপনার যদি প্রয়োজন হয় তবে আপনার একটি পূর্ণ বৈশিষ্ট্যযুক্ত টেম্প্লেটিং লাইব্রেরি দরকার।
আন্দ্রে সিওবানু

2

অ্যাপাচি কমন্স ল্যাং-এর প্রতিস্থাপন পদ্ধতিটি আপনার নির্দিষ্ট প্রয়োজনের উপর নির্ভরশীল হতে পারে। আপনি এই একক পদ্ধতি কল দিয়ে নাম সহ স্থানধারককে প্রতিস্থাপন করতে সহজেই এটি ব্যবহার করতে পারেন:

StringUtils.replaceEach("There's an incorrect value '%(value)' in column # %(column)",
            new String[] { "%(value)", "%(column)" }, new String[] { x, y });

কিছু ইনপুট পাঠ্য দেওয়া হয়েছে, এটি প্রথম স্ট্রিং অ্যারেতে স্থানধারীদের সমস্ত উপস্থিতিকে দ্বিতীয়টির সাথে সম্পর্কিত মানগুলির সাথে প্রতিস্থাপন করবে।


1

আপনার স্ট্রিং সহায়ক শ্রেণিতে এমন কিছু থাকতে পারে

/**
 * An interpreter for strings with named placeholders.
 *
 * For example given the string "hello %(myName)" and the map <code>
 *      <p>Map<String, Object> map = new HashMap<String, Object>();</p>
 *      <p>map.put("myName", "world");</p>
 * </code>
 *
 * the call {@code format("hello %(myName)", map)} returns "hello world"
 *
 * It replaces every occurrence of a named placeholder with its given value
 * in the map. If there is a named place holder which is not found in the
 * map then the string will retain that placeholder. Likewise, if there is
 * an entry in the map that does not have its respective placeholder, it is
 * ignored.
 *
 * @param str
 *            string to format
 * @param values
 *            to replace
 * @return formatted string
 */
public static String format(String str, Map<String, Object> values) {

    StringBuilder builder = new StringBuilder(str);

    for (Entry<String, Object> entry : values.entrySet()) {

        int start;
        String pattern = "%(" + entry.getKey() + ")";
        String value = entry.getValue().toString();

        // Replace every occurence of %(key) with value
        while ((start = builder.indexOf(pattern)) != -1) {
            builder.replace(start, start + pattern.length(), value);
        }
    }

    return builder.toString();
}

অনেক অনেক ধন্যবাদ, আমি যা চাই তা প্রায় এটি করে তবে কেবলমাত্র এটি পরিবর্তনকারী হিসাবে অ্যাকাউন্ট করে না ("% (কী) 08 ডি" বিবেচনা করুন)
অ্যান্ডি

1
এটিও নোট করুন যে ব্যবহার করা মানগুলির মধ্যে কোনওটি যদি সংশ্লিষ্ট এন্ট্রি ধারণ করে তবে এটি অসীম লুপে যায়।
অ্যারন ডুফর

1
সতর্কতা: যেহেতু লুপটি মধ্যবর্তী প্রতিস্থাপনের ফলাফলগুলিকে তাদের নিজস্ব ফর্ম্যাট স্ট্রিং হিসাবে বিবেচনা করে, তাই এই সমাধানটি স্ট্রিং আক্রমণগুলিকে বিন্যাস করতে ঝুঁকিপূর্ণ । যে কোনও সঠিক সমাধান ফর্ম্যাট স্ট্রিংয়ের মাধ্যমে একটি একক পাস করা উচিত।
200_সুকেস

1

আমার উত্তরটি হ'ল:

ক) সম্ভব হলে স্ট্রিংবিল্ডার ব্যবহার করুন

খ) "স্থানধারক" এর অবস্থান (যে কোনও আকারে: পূর্ণসংখ্যাটি সেরা, বিশেষ চর যেমন ডলার ম্যাক্রো ইত্যাদি) রাখুন এবং তারপরে ব্যবহার করুন StringBuilder.insert()(যুক্তিগুলির কয়েকটি সংস্করণ)।

বাইরের লাইব্রেরিগুলি ব্যবহার করা ওভারকিল বলে মনে হয় এবং আমি স্ট্রিংবিল্ডারকে অভ্যন্তরীণভাবে স্ট্রিংয়ে রূপান্তরিত করা হলে পারফরম্যান্সকে হ্রাস করে।


1

আমি ক্লাস তৈরি করা উত্তরের উপর ভিত্তি করে MapBuilder:

public class MapBuilder {

    public static Map<String, Object> build(Object... data) {
        Map<String, Object> result = new LinkedHashMap<>();

        if (data.length % 2 != 0) {
            throw new IllegalArgumentException("Odd number of arguments");
        }

        String key = null;
        Integer step = -1;

        for (Object value : data) {
            step++;
            switch (step % 2) {
                case 0:
                    if (value == null) {
                        throw new IllegalArgumentException("Null key value");
                    }
                    key = (String) value;
                    continue;
                case 1:
                    result.put(key, value);
                    break;
            }
        }

        return result;
    }

}

তারপরে আমি StringFormatস্ট্রিং ফর্ম্যাটিংয়ের জন্য ক্লাস তৈরি করেছি :

public final class StringFormat {

    public static String format(String format, Object... args) {
        Map<String, Object> values = MapBuilder.build(args);

        for (Map.Entry<String, Object> entry : values.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            format = format.replace("$" + key, value.toString());
        }

        return format;
    }

}

যা আপনি এটির মতো ব্যবহার করতে পারেন:

String bookingDate = StringFormat.format("From $startDate to $endDate"), 
        "$startDate", formattedStartDate, 
        "$endDate", formattedEndDate
);

1
সতর্কতা: যেহেতু লুপটি মধ্যবর্তী প্রতিস্থাপনের ফলাফলগুলিকে তাদের নিজস্ব ফর্ম্যাট স্ট্রিং হিসাবে বিবেচনা করে, তাই এই সমাধানটি স্ট্রিং আক্রমণগুলিকে বিন্যাস করতে ঝুঁকিপূর্ণ । যে কোনও সঠিক সমাধান ফর্ম্যাট স্ট্রিংয়ের মাধ্যমে একটি একক পাস করা উচিত।
200_সুকেস

1

আমি একটি ইউজার / হেল্পার ক্লাসও তৈরি করেছি (jdk 8 ব্যবহার করে) যা একটি স্ট্রিংকে ভেরিয়েবলের উপস্থিতিগুলির পরিবর্তে ফর্ম্যাট করতে পারে।

এই উদ্দেশ্যে আমি ম্যাচার্স "অ্যাপেন্ড্রেস রিপ্লেসমেন্ট" পদ্ধতিটি ব্যবহার করেছি যা সমস্ত প্রতিস্থাপন করে এবং কেবলমাত্র একটি বিন্যাসের স্ট্রিংয়ের প্রভাবিত অংশের উপরে লুপ করে।

সহায়ক শ্রেণি বর্তমানে জাভাদোক নথিভুক্ত নয়। আমি ভবিষ্যতে এটি পরিবর্তন করব;) যাইহোক আমি সর্বাধিক গুরুত্বপূর্ণ রেখাগুলি মন্তব্য করেছি (আশা করি)।

    public class FormatHelper {

    //Prefix and suffix for the enclosing variable name in the format string.
    //Replace the default values with any you need.
    public static final String DEFAULT_PREFIX = "${";
    public static final String DEFAULT_SUFFIX = "}";

    //Define dynamic function what happens if a key is not found.
    //Replace the defualt exception with any "unchecked" exception type you need or any other behavior.
    public static final BiFunction<String, String, String> DEFAULT_NO_KEY_FUNCTION =
            (fullMatch, variableName) -> {
                throw new RuntimeException(String.format("Key: %s for variable %s not found.",
                                                         variableName,
                                                         fullMatch));
            };
    private final Pattern variablePattern;
    private final Map<String, String> values;
    private final BiFunction<String, String, String> noKeyFunction;
    private final String prefix;
    private final String suffix;

    public FormatHelper(Map<String, String> values) {
        this(DEFAULT_NO_KEY_FUNCTION, values);
    }

    public FormatHelper(
            BiFunction<String, String, String> noKeyFunction, Map<String, String> values) {
        this(DEFAULT_PREFIX, DEFAULT_SUFFIX, noKeyFunction, values);
    }

    public FormatHelper(String prefix, String suffix, Map<String, String> values) {
        this(prefix, suffix, DEFAULT_NO_KEY_FUNCTION, values);
    }

    public FormatHelper(
            String prefix,
            String suffix,
            BiFunction<String, String, String> noKeyFunction,
            Map<String, String> values) {
        this.prefix = prefix;
        this.suffix = suffix;
        this.values = values;
        this.noKeyFunction = noKeyFunction;

        //Create the Pattern and quote the prefix and suffix so that the regex don't interpret special chars.
        //The variable name is a "\w+" in an extra capture group.
        variablePattern = Pattern.compile(Pattern.quote(prefix) + "(\\w+)" + Pattern.quote(suffix));
    }

    public static String format(CharSequence format, Map<String, String> values) {
        return new FormatHelper(values).format(format);
    }

    public static String format(
            CharSequence format,
            BiFunction<String, String, String> noKeyFunction,
            Map<String, String> values) {
        return new FormatHelper(noKeyFunction, values).format(format);
    }

    public static String format(
            String prefix, String suffix, CharSequence format, Map<String, String> values) {
        return new FormatHelper(prefix, suffix, values).format(format);
    }

    public static String format(
            String prefix,
            String suffix,
            BiFunction<String, String, String> noKeyFunction,
            CharSequence format,
            Map<String, String> values) {
        return new FormatHelper(prefix, suffix, noKeyFunction, values).format(format);
    }

    public String format(CharSequence format) {

        //Create matcher based on the init pattern for variable names.
        Matcher matcher = variablePattern.matcher(format);

        //This buffer will hold all parts of the formatted finished string.
        StringBuffer formatBuffer = new StringBuffer();

        //loop while the matcher finds another variable (prefix -> name <- suffix) match
        while (matcher.find()) {

            //The root capture group with the full match e.g ${variableName}
            String fullMatch = matcher.group();

            //The capture group for the variable name resulting from "(\w+)" e.g. variableName
            String variableName = matcher.group(1);

            //Get the value in our Map so the Key is the used variable name in our "format" string. The associated value will replace the variable.
            //If key is missing (absent) call the noKeyFunction with parameters "fullMatch" and "variableName" else return the value.
            String value = values.computeIfAbsent(variableName, key -> noKeyFunction.apply(fullMatch, key));

            //Escape the Map value because the "appendReplacement" method interprets the $ and \ as special chars.
            String escapedValue = Matcher.quoteReplacement(value);

            //The "appendReplacement" method replaces the current "full" match (e.g. ${variableName}) with the value from the "values" Map.
            //The replaced part of the "format" string is appended to the StringBuffer "formatBuffer".
            matcher.appendReplacement(formatBuffer, escapedValue);
        }

        //The "appendTail" method appends the last part of the "format" String which has no regex match.
        //That means if e.g. our "format" string has no matches the whole untouched "format" string is appended to the StringBuffer "formatBuffer".
        //Further more the method return the buffer.
        return matcher.appendTail(formatBuffer)
                      .toString();
    }

    public String getPrefix() {
        return prefix;
    }

    public String getSuffix() {
        return suffix;
    }

    public Map<String, String> getValues() {
        return values;
    }
}

আপনি নির্দিষ্ট মানচিত্রের জন্য মানগুলি (বা প্রত্যয় উপসর্গ বা noKeyFunction) এর মতো শ্রেণীর উদাহরণ তৈরি করতে পারেন:

    Map<String, String> values = new HashMap<>();
    values.put("firstName", "Peter");
    values.put("lastName", "Parker");


    FormatHelper formatHelper = new FormatHelper(values);
    formatHelper.format("${firstName} ${lastName} is Spiderman!");
    // Result: "Peter Parker is Spiderman!"
    // Next format:
    formatHelper.format("Does ${firstName} ${lastName} works as photographer?");
    //Result: "Does Peter Parker works as photographer?"

আরও মানচিত্রের কীটি অনুপস্থিত থাকলে কী হবে তা আপনি সংজ্ঞা দিয়ে দিতে পারেন (উভয় উপায়ে কাজ করে যেমন ফর্ম্যাট স্ট্রিংয়ে ভুল ভেরিয়েবলের নাম বা মানচিত্রে কী হারিয়ে যাওয়া)। ডিফল্ট আচরণটি একটি ছোঁড়া চেক করা ব্যতিক্রম (চেক করা হয়নি কারণ আমি ডিফল্ট jdk8 ফাংশন যা চেক ব্যতিক্রমগুলি পরিচালনা করতে পারে না) এর মত:

    Map<String, String> map = new HashMap<>();
    map.put("firstName", "Peter");
    map.put("lastName", "Parker");


    FormatHelper formatHelper = new FormatHelper(map);
    formatHelper.format("${missingName} ${lastName} is Spiderman!");
    //Result: RuntimeException: Key: missingName for variable ${missingName} not found.

আপনি যেমন কন্সট্রাক্টর কলটিতে একটি কাস্টম আচরণ নির্ধারণ করতে পারেন:

Map<String, String> values = new HashMap<>();
values.put("firstName", "Peter");
values.put("lastName", "Parker");


FormatHelper formatHelper = new FormatHelper(fullMatch, variableName) -> variableName.equals("missingName") ? "John": "SOMETHING_WRONG", values);
formatHelper.format("${missingName} ${lastName} is Spiderman!");
// Result: "John Parker is Spiderman!"

বা এটিকে ডিফল্টতে ফিরিয়ে দিন কোনও মূল আচরণ নেই:

...
    FormatHelper formatHelper = new FormatHelper((fullMatch, variableName) ->   variableName.equals("missingName") ? "John" :
            FormatHelper.DEFAULT_NO_KEY_FUNCTION.apply(fullMatch,
                                                       variableName), map);
...

আরও ভাল পরিচালনা করার জন্য স্থির পদ্ধতির উপস্থাপনা যেমন:

Map<String, String> values = new HashMap<>();
values.put("firstName", "Peter");
values.put("lastName", "Parker");

FormatHelper.format("${firstName} ${lastName} is Spiderman!", map);
// Result: "Peter Parker is Spiderman!"

1

এটি লেখার মুহুর্তে জাভাতে তৈরির কোনও কিছুই নেই। আমি আপনার নিজের প্রয়োগটি লেখার পরামর্শ দেব। আমার পছন্দটি মানচিত্র তৈরির পরিবর্তে এটি কার্যকর করার পরিবর্তে একটি সহজ সাবলীল নির্মাতা ইন্টারফেসের জন্য - আপনি কোডের একটি সুন্দর সংলগ্ন অংশটি দিয়ে শেষ করেন, উদাহরণস্বরূপ:

String result = new TemplatedStringBuilder("My name is {{name}} and I from {{town}}")
   .replace("name", "John Doe")
   .replace("town", "Sydney")
   .finish();

এখানে একটি সহজ বাস্তবায়ন:

class TemplatedStringBuilder {

    private final static String TEMPLATE_START_TOKEN = "{{";
    private final static String TEMPLATE_CLOSE_TOKEN = "}}";

    private final String template;
    private final Map<String, String> parameters = new HashMap<>();

    public TemplatedStringBuilder(String template) {
        if (template == null) throw new NullPointerException();
        this.template = template;
    }

    public TemplatedStringBuilder replace(String key, String value){
        parameters.put(key, value);
        return this;
    }

    public String finish(){

        StringBuilder result = new StringBuilder();

        int startIndex = 0;

        while (startIndex < template.length()){

            int openIndex  = template.indexOf(TEMPLATE_START_TOKEN, startIndex);

            if (openIndex < 0){
                result.append(template.substring(startIndex));
                break;
            }

            int closeIndex = template.indexOf(TEMPLATE_CLOSE_TOKEN, openIndex);

            if(closeIndex < 0){
                result.append(template.substring(startIndex));
                break;
            }

            String key = template.substring(openIndex + TEMPLATE_START_TOKEN.length(), closeIndex);

            if (!parameters.containsKey(key)) throw new RuntimeException("missing value for key: " + key);

            result.append(template.substring(startIndex, openIndex));
            result.append(parameters.get(key));

            startIndex = closeIndex + TEMPLATE_CLOSE_TOKEN.length();
        }

        return result.toString();
    }
}

0

ফ্রিমার্কার , টেম্প্লেটিং লাইব্রেরি চেষ্টা করুন ।

বিকল্প পাঠ


4
Freemarker? আমার ধারণা, তিনি জানতে চান, কীভাবে সরল জাভাতে এটি করা যায়। যাইহোক ফ্রিমার্কার যদি সম্ভাব্য উত্তর হয় তবে আমি কী বলতে পারি জেএসপিও সঠিক উত্তর হবে?
রাকেশ জুয়াল

1
ধন্যবাদ, তবে আমার কাজটির জন্য এটি একরকম ওভারকিলের মতো বলে মনে হচ্ছে। কিন্তু ধন্যবাদ.
অ্যান্ডি

1
@ রাকেশ জেএসপি একটি খুব "ভিউ / এফই" নির্দিষ্ট জিনিস। আমি এক্সএমএল উত্পন্ন করার জন্য ফ্রিমার্কার অতীতে ব্যবহার করেছি এবং কখনও কখনও এমনকি জেভিএ ফাইলগুলি উত্পন্ন করেছিলাম। অ্যান্ডি ভয় পাচ্ছেন যে আপনাকে একটি ইউটিলিটি নিজে লিখতে হবে (বা উপরে উল্লিখিতগুলির মতো)
কান্নান একনাথ

@ বোরিস, বেগ ও বনাম স্ট্রিংটেমপ্লেট আরও ভাল ফ্রি-মার্কার কোনটি?
গৌরব


0

https://dzone.com/articles/java-string-format-exferences স্ট্রিং. ফর্ম্যাট (ইনপুটস্ট্রিং, [listOfParams]) সবচেয়ে সহজ উপায় হবে। স্ট্রিং মধ্যে স্থানধারীদের অর্ডার দ্বারা সংজ্ঞায়িত করা যেতে পারে। আরও তথ্যের জন্য প্রদত্ত লিঙ্কটি পরীক্ষা করুন।


0

আপনার অফিশিয়াল আইসিইউ 4 জে লাইব্রেরিটি দেখে নেওয়া উচিত । এটি জেডিকে-র মতো উপলব্ধ মেসেজফর্ম্যাট ক্লাস সরবরাহ করে তবে এই প্রাক্তন সমর্থিত নামধারীদের সমর্থন করে।

এই পৃষ্ঠায় প্রদত্ত অন্যান্য সমাধানগুলির মতো নয়। আইসিইউ 4 জে আইসিইউ প্রকল্পের অংশ যা আইবিএম দ্বারা রক্ষণাবেক্ষণ করা হয় এবং নিয়মিত আপডেট হয়। এছাড়াও, এটি বহুগুণকরণ এবং আরও অনেক কিছু হিসাবে উন্নত ব্যবহারের ক্ষেত্রে সমর্থন করে।

এখানে একটি কোড উদাহরণ:

MessageFormat messageFormat =
        new MessageFormat("Publication written by {author}.");

Map<String, String> args = Map.of("author", "John Doe");

System.out.println(messageFormat.format(args));

0

জাভাতে স্ট্রিং ইন্টারপোলেশন ব্যবহার করার জন্য জাভা প্লাগইন রয়েছে (যেমন কোটলিন, জাভাস্ক্রিপ্টে)। সমর্থন জাভা 8, 9, 10, 11 ... https://github.com/antkorwin/better-strings

স্ট্রিং লিটারেলগুলিতে ভেরিয়েবল ব্যবহার করা:

int a = 3;
int b = 4;
System.out.println("${a} + ${b} = ${a+b}");

এক্সপ্রেশন ব্যবহার:

int a = 3;
int b = 4;
System.out.println("pow = ${a * a}");
System.out.println("flag = ${a > b ? true : false}");

ফাংশন ব্যবহার করে:

@Test
void functionCall() {
    System.out.println("fact(5) = ${factorial(5)}");
}

long factorial(int n) {
    long fact = 1;
    for (int i = 2; i <= n; i++) {
        fact = fact * i;
    }
    return fact;
}

আরও তথ্যের জন্য, দয়া করে প্রকল্পটি পড়ুন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.