كيف يمكنني إلحاق حرف السطر الجديد على جميع الخطوط ما عدا آخر واحد ؟

StackOverflow https://stackoverflow.com/questions/448320

  •  19-08-2019
  •  | 
  •  

سؤال

أنا بالتكرار خلال HashMap (انظر سؤالي السابق لمزيد من التفاصيل) وبناء سلسلة تتكون من البيانات الواردة في خريطة.لكل بند سوف يكون خط جديد, ولكن على البند الأخير ، أنا لا أريد الخط الجديد.كيف يمكنني تحقيق ذلك ؟ كنت أفكر في أن ذلك نوع من تحقق لمعرفة ما إذا كان إدخال آخر أم لا, لكنني لست متأكدا من كيفية القيام بذلك.

وذلك بفضل!

هل كانت مفيدة؟

المحلول

وتغيير عملية التفكير بك من "إلحاق خط كسر جميع ولكن في المرة الأخيرة" إلى "إلحاقها خط كسر جميع لكنها المرة الأولى":

boolean first = true;
StringBuilder builder = new StringBuilder();

for (Map.Entry<MyClass.Key,String> entry : data.entrySet()) {
    if (first) {
        first = false;
    } else {
        builder.append("\n"); // Or whatever break you want
    }
    builder.append(entry.key())
           .append(": ")
           .append(entry.value());
}

نصائح أخرى

وأسلوب واحد (مع الاعتذار لجون السكيت للاقتراض جزء من شفرة جافا وسلم):

StringBuilder result = new StringBuilder();

string newline = "";  
for (Map.Entry<MyClass.Key,String> entry : data.entrySet())
{
    result.append(newline)
       .append(entry.key())
       .append(": ")
       .append(entry.value());

    newline = "\n";
}

وماذا عن هذا؟

StringBuilder result = new StringBuilder();

for(Map.Entry<MyClass.Key,String> entry : data.entrySet())
{
    builder.append(entry.key())
       .append(": ")
       .append(entry.value())
       .append("\n");
}

return builder.substring(0, builder.length()-1);

والاعتذار الإجبارية وبفضل كل من جون وجويل ل "الاقتراض" من الأمثلة الخاصة بهم.

وUsusally لهذا النوع من الأشياء التي أستخدمها اباتشي-العموم لانغ <لأ href = "http://commons.apache.org/lang/api/org/apache/commons/lang/StringUtils.html#join(java .util.Collection،٪ 20java.lang.String) "يختلط =" noreferrer "> StringUtils # الانضمام . وفي حين أنه ليس من الصعب حقا لكتابة كل هذه الأنواع من الوظائف فائدة، فإنه من الأفضل دائما لإعادة المكتبات المعتمدة الحالية. أباتشي-المشاعات مليء الاشياء المفيدة مثل ذلك!

إذا كنت تستخدم مكرر بدلا من ل... كل التعليمات البرمجية الخاصة بك يمكن أن تبدو مثل هذا:

StringBuilder builder = new StringBuilder();

Iterator<Map.Entry<MyClass.Key, String>> it = data.entrySet().iterator();

while (it.hasNext()) {
    Map.Entry<MyClass.Key, String> entry = it.next();

    builder.append(entry.key())
    .append(": ")
    .append(entry.value());

    if (it.hasNext()) {
        builder.append("\n");
    }
}

وربما هذا هو أفضل مثال ...

final StringBuilder buf = new StringBuilder();
final String separator = System.getProperty("line.separator"); // Platform new line
for (Map.Entry<MyClass.Key,String> entry: data.entrySet()) {
    builder.append(entry.key())
       .append(": ")
       .append(entry.value())
       .append(separator);
}
// Remove the last separator and return a string to use.
// N.b. this is likely as efficient as just using builder.toString() 
// which would also copy the buffer, except we have 1 char less 
// (i.e. '\n').
final String toUse = builder.substring(0, builder.length()-separator.length()-1);

وهنا لي نسخة مقتضبة، والذي يستخدم خاصية طول ب StringBuilder بدلا من متغير إضافي:

StringBuilder builder = new StringBuilder();

for (Map.Entry<MyClass.Key,String> entry : data.entrySet())
{
    builder.append(builder.length() > 0 ? "\n" : "")
           .append(entry.key())
           .append(": ")
           .append(entry.value());
}

و(الاعتذار والشكر إلى كل من جون وجويل ل "الاقتراض" من الأمثلة الخاصة بهم.)

حل واحد هو إنشاء مخصص المجمع إلى بـ stringbuilder.لا يمكن تمديده ، وبالتالي المجمع هو مطلوب.

public class CustomStringBuilder {

final String separator = System.getProperty("line.separator");

private StringBuilder builder = new StringBuilder();

public CustomStringBuilder appendLine(String str){
    builder.append(str + separator);
    return this;
}

public CustomStringBuilder append(String str){
    builder.append(str);
    return this;
}

public String toString() {
    return this.builder.toString();
}

}

تنفيذ مثل هذه:

CustomStringBuilder builder = new CustomStringBuilder();

//iterate over as needed, but a wrapper to StringBuilder with new line features.

builder.appendLine("data goes here");
return builder.toString();

هذه بعض سلبيات:

  • كتابة التعليمات البرمجية التي عادة لا "المجال / الأعمال" التي تركز على
  • لا تستخدم المصادر المفتوحة حل القياسية مثل:StringUtils.الانضمام
  • اضطر للحفاظ على الطبقة التي يلف JDK الفصل النهائي وبالتالي التحديثات المطلوبة على المدى الطويل.

ذهبت مع StringUtils.الانضمام إلى الحل بالتكرار على مجموعات حتى بناء خفيفة الوزن بناء الأسلوب في أنماط الرمز.

وعلى افتراض حلقة foreach بك يمر عبر ملف من أجل مجرد إضافة خط جديد إلى كل سلسلة وإزالة الخط الجديد الماضي عندما مخارج حلقة الخاص بك.

ولست متأكدا إذا كان هذا هو الأفضل، ولكن؟ ق أسهل طريقة للقيام:

ويتكرر خلال كل القيم وإلحاق \ ن عادة في stringbuffer. ثم، لا شيء من هذا القبيل

sb.setLength(sb.length()-1); 

وهذا هو المكان الذي ينضم طريقة، لاستكمال الانقسام، من شأنها أن تأتي في متناول اليدين، لأن ثم هل يمكن أن مجرد انضمام جميع العناصر باستخدام سطر جديد كفاصل، وبالطبع فإنه لا إلحاق خط جديد إلى نهاية من النتيجة. كيف لي ان تفعل ذلك في مختلف لغات البرمجة (جافا سكريبت، PHP، الخ.).

إذا كنت تستخدم الدرجة فاصل ، كنت يمكن القيام به

StringBuilder buf = new StringBuilder();
Separator separator = new Separator("\n");
for (Map.Entry<MyClass.Key,String> entry: data.entrySet()) {
    builder.append(separator)
       .append(entry.key())
       .append(": ")
       .append(entry.value());
}

ويطبع فاصل في سلسلة فارغة على أول استخدام لها، والفاصل على جميع الاستخدامات اللاحقة.

وها! بفضل هذا المنصب لقد وجدت طريقة أخرى للقيام بذلك:

public static class Extensions
{
    public static string JoinWith(this IEnumerable<string> strings, string separator)
    {
        return String.Join(separator, strings.ToArray());
    }
}

وبالطبع هذا في C # الآن وجافا لن (حتى الآن) دعم طريقة التمديد، ولكن يجب عليك أن تكون قادرة على التكيف حسب الحاجة - الشيء الرئيسي هو استخدام String.Join على أي حال، وأنا متأكد جافا لديه بعض التناظرية لذلك.

لاحظ أيضا أن هذا يعني القيام على تكرار إضافي من السلاسل، لأنه يجب أولا إنشاء مجموعة ثم أعاد على أنه من أجل بناء سلسلة الخاص بك. أيضا، <م> سوف إنشاء مجموعة، حيث مع بعض الأساليب الأخرى التي قد تكون قادرة على الحصول عليه مع IEnumerable أن يحمل سوى سلسلة واحدة في الذاكرة في وقت واحد. ولكن أنا حقا أحب الوضوح اضافية.

وبطبيعة الحال، نظرا لقدرة طريقة تمديد هل يمكن فقط مجردة أي من تعليمات برمجية أخرى إلى أسلوب تمديد كذلك.

واسمحوا المكتبات القيام بذلك نيابة عنك.

import com.sun.deploy.util.StringUtils;

وكذلك العديد من البعض الآخر StringUtils، التي لديها طريقة الانضمام. يمكنك القيام بذلك في سطر واحد:

StringUtils.join(list, DELIMITER);

ولكن لمزيد من السياق، وهنا هو كيف يمكن أن تفعل ذلك مع hashmap.

public static String getDelimitatedData(HashMap<String, String> data) {
    final String DELIMITER = "\n"; //Should make this a variable
    ArrayList<String> entries = new ArrayList<>();

    for (Map.Entry<String, String> entry : data.entrySet()) {
        entries.add(entry.getKey() + ": " + entry.getValue());
    }

    return StringUtils.join(entries, DELIMITER);
}

استخدم سلسلة JDK الانضمام واجهات برمجة التطبيقات:

String result = data.stream()
    .map((k,v) -> String.format("%s : %s", k, v)
    .collect(Collectors.joining("\n"));
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top