Bir StringBuilder son karakteri kaldırılsın mı?


423

Bir koleksiyonda döngüye girmeniz ve her bir veriyi bir sınırlayıcıyla ayrılmış bir dize yapmanız gerektiğinde, sonunda her zaman ekstra bir sınırlayıcı ile karşılaşırsınız;

for (String serverId : serverIds) {
  sb.append(serverId);
   sb.append(",");
}

Şöyle bir şey verir: serverId_1, serverId_2, serverId_3,

StringBuilder son karakteri silmek istiyorum (ben hala bu döngüden sonra gerek çünkü dönüştürmeden).


11
Dizeleri birleştirerek "dize birleştirme" anlamına geliyorsa, dizelerin sayısına ve uzunluklarına bağlıdır. Dizeleri değişmez olduğundan, boyutlarından bağımsız olarak çok sayıda dizede çekiçlenecekseniz, bir dize oluşturucu kullanmak daha etkilidir. Dizeleri her birleştirdiğinizde, yeni bir sonuç dizesi oluşturursunuz (bu gerçekten bir char dizisidir). Dize oluşturucular temelde toString () yöntemini çağırana kadar değişmez bir dize haline gelmeyen bir char listesidir.
dyslexicanaboko

4
Java 8 kullanıyorsanız, şunu kullanın StringJoiner: stackoverflow.com/a/29169233/901641
ArtOfWarfare

Yanıtlar:


640

Diğerleri deleteCharAtyöntemi işaret etti , ancak burada başka bir alternatif yaklaşım var:

String prefix = "";
for (String serverId : serverIds) {
  sb.append(prefix);
  prefix = ",";
  sb.append(serverId);
}

Alternatif olarak, GuavaJoiner sınıfını kullanın :)

Java 8'den StringJoineritibaren, standart JRE'nin bir parçasıdır.


7
@Coronatus: Hayır, çünkü "" tek bir karakter değil, herhangi bir karakterin olmamasıdır .
Jon Skeet

31
= "," önekini yürütmez; Her döngü döngüsü performansı etkiler mi?
Harish

21
@Harish: Muhtemelen, küçük, küçük bir parça - yine de önemli olması pek olası değil.
Jon Skeet

4
@Harish - ve muhtemelen optimize edici ilk döngü yinelemesini kaldırırsa.
Stephen C

6
Apache Commons Guava var için başka bir alternatif var Joineronların çok StringUtils. commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/… , java.lang.String)
GoRoS

419

Başka bir basit çözüm:

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

Daha karmaşık bir çözüm:

Yukarıdaki çözüm sb.length() > 0... yani kaldırılacak bir "son karakter" olduğunu varsayar . Bu varsayımı yapamazsanız ve / veya varsayım yanlışsa ortaya çıkacak istisna ile başa çıkamazsanız, önce StringBuilder'ın uzunluğunu kontrol edin; Örneğin

// Readable version
if (sb.length() > 0) {
   sb.setLength(sb.length() - 1);
}

veya

// Concise but harder-to-read version of the above.
sb.setLength(Math.max(sb.length() - 1, 0));

23
Çok güzel bir çözüm. Performans üzerinde en düşük etki ve en az kod gerekli :)
Alain O'Dea

186
if(sb.length() > 0){
    sb.deleteCharAt(sb.length() - 1);
}

33
Bu çok fazla yükseltildi, ancak verimli değil, bir sistem yapıyor. @Rohit Reddy Korrapolu ne dedi.
alianos-

13
Aynı sb.length() == 0zamanda güvensiz
Matthias

Oyundaki yedek çift karakterlerle bu güvenli midir?
rogerdpack

Son karakterin virgül ayırıcı olduğunu varsayarsak (örneğe göre), suretler hiçbir fark yaratmaz. Genelleştirmeniz gerekiyorsa separator.length()1 yerine çıkarın .
Stephen C

61

Java 8'den itibaren String sınıfının statik bir yöntemi vardır join. İlk argüman, her bir dize çifti arasında istediğiniz bir dizedir ve ikincisi Iterable<CharSequence>(her ikisi de arayüzdür, bu yüzden List<String>çalışır gibi bir şeydir) .

String.join(",", serverIds);

Ayrıca Java 8'de, StringJoineriçine yerleştirilecek öğelerin tam listesine sahip olmadan önce dizeyi oluşturmaya başlamak istediğiniz senaryolar için yeni sınıfı kullanabilirsiniz .


Eğer sakıncası yoksa nvm sizin için düzenlenmiş, benim yorum da kaldırıldı
Eugene

@Eugene - Cevabı odaklanmak String.joinyerine tamamen yeniden yazdım StringJoiner.
ArtOfWarfare

37

Sadece son karakter oluşumunun pozisyonunu alın.

for(String serverId : serverIds) {
 sb.append(serverId);
 sb.append(",");
}
sb.deleteCharAt(sb.lastIndexOf(","));

Yana lastIndexOfbir ters arama gerçekleştirmek ve bunu ilk seferde bulacaksınız bilecek, performans burada bir sorun olmayacaktır.

DÜZENLE

Cevabımı (teşekkürler millet 😊) almak devam beri, bu konuda değer:

On Java 8 ileriye sadece daha okunaklı ve kullanımı açık olacaktır StringJoiner . Basit bir ayırıcı için bir yöntemi ve önek ve sonek için aşırı yükleme vardır.

Buradan alınan örnekler: örnek

Basit ayırıcı kullanan örnek:

    StringJoiner mystring = new StringJoiner("-");    

    // Joining multiple strings by using add() method  
    mystring.add("Logan");  
    mystring.add("Magneto");  
    mystring.add("Rogue");  
    mystring.add("Storm");  

    System.out.println(mystring);

Çıktı:

Logan-Manyeto-Rogue-Fırtına

Sonek ve önek içeren örnek:

    StringJoiner mystring = new StringJoiner(",", "(", ")");    

    // Joining multiple strings by using add() method  
    mystring.add("Negan");  
    mystring.add("Rick");  
    mystring.add("Maggie");  
    mystring.add("Daryl");  

    System.out.println(mystring);

Çıktı

(Negan Rick Maggie Daryl)


Son karakterin bir ,olduğundan emin olursunuz çünkü bu son karakterin son ifadesiydi for loop. Daha lastInfexOffazla okunabilirlik ve 0 dizinli olup olmadığını hatırlamak istemiyorsanız bunu bir beyinsiz yapmaktır. Ayrıca, stringbuilder uzunluğunu karıştırmanıza gerek yoktur. Sadece rahatlık için.
Reuel Ribeiro

34

Bu durumda,

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

, '\0'son karakteri silmek için son değeri atadığı için tercih edilir.System.arraycopy


1
setLengthÇağrı geçen değere şey atama değildir. Java dize arabellekleri null / zero sonlandırılmaz. Aslında, setLengthsadece bir lengthalanı güncelliyor .
Stephen C

@Rohit Reddy Korrapolu: Ama arraycopykopyalar 0 element, bu yüzden sanırım optimize edilebilir.
maaartinus

2
NewLength bağımsız değişkeni geçerli uzunluktan büyük veya ona eşitse, uzunluk newLength bağımsız değişkeni olacak şekilde yeterli boş karakterler ('\ u0000') eklenir. Bu durum böyle değil.
14'te fglez


11

Başka bir alternatif

for(String serverId : serverIds) {
   sb.append(",");
   sb.append(serverId); 
}
sb.deleteCharAt(0);

2
Boyut hesaplamaları gerektirdiğinden, son karakteri kaldırmaktan daha iyi olmalıdır. İlk karakter kaldırılmadıkça verilerin taşınmasına neden olmadıkça ...
slott

8

Alternatif olarak,

StringBuilder result = new StringBuilder();
for(String string : collection) {
    result.append(string);
    result.append(',');
}
return result.substring(0, result.length() - 1) ;

Bir "." Ekleyebildiğiniz için kullanılabilir sonunda.
artfullyContrived

6
StringBuilder sb = new StringBuilder();
sb.append("abcdef");
sb.deleteCharAt(sb.length() - 1);
assertEquals("abcde",sb.toString());
// true

5

Yine başka bir alternatif:

public String join(Collection<String> collection, String seperator) {
    if (collection.isEmpty()) return "";

    Iterator<String> iter = collection.iterator();
    StringBuilder sb = new StringBuilder(iter.next());
    while (iter.hasNext()) {
        sb.append(seperator);
        sb.append(iter.next());
    }

    return sb.toString();
}

3

Kullanımın yeniden prefixbaşlatılmasını (performansı etkiler) önlemek için TextUtils.isEmpty öğesini kullanın:

            String prefix = "";
            for (String item : list) {
                sb.append(prefix);
                if (TextUtils.isEmpty(prefix))
                    prefix = ",";
                sb.append(item);
            }

TestUtils ne tür bir pakete aittir?
Markus

@Markus android.text.TextUtils
NickUnuchek

1

Oluşturduğunuz metinden son karakteri kaldırmak yerine 'Joiner' sınıfını kullanmayı deneyebilirsiniz;

                List<String> textList = new ArrayList<>();
                textList.add("text1");
                textList.add("text2");
                textList.add("text3");

                Joiner joiner = Joiner.on(",").useForNull("null");
                String output = joiner.join(textList);

               //output : "text1,text2,text3"

1

Aşağıdaki gibi bir şey yapıyorum:

    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 0; i < value.length; i++) {
        stringBuilder.append(values[i]);
        if (value.length-1) {
            stringBuilder.append(", ");
        }
    }

0

İşte başka bir çözüm:

for(String serverId : serverIds) {
   sb.append(",");
   sb.append(serverId); 
}

String resultingString = "";
if ( sb.length() > 1 ) {
    resultingString = sb.substring(1);
}

1
Ah anlıyorum. Dize değil StringBuilder alt dize çağırıyorsunuz.
Stephen C

Her neyse, bu Zaki'nin 2010'daki çözümüne sadece küçük bir varyantı.
Stephen C

0

Şahsen sonunda bir geri karakteri (veya daha uzun "sınırlayıcı" için daha fazla) eklemek istiyorum:

for(String serverId : serverIds) {
    sb.append(serverId);
    sb.append(",");
}

sb.append('\b');

Sorunları olduğunu unutmayın:

  • nasıl \bgörüntüleneceği ortama bağlıdır,
  • length()ait Stringiçerik "visibile" karakter uzunluğunda farklı olabilir

Ne zaman \bgörünüyor Tamam ve uzunluk böyle bir konsoluna giriş olarak önemli değil, bu benim için iyi yeterince görünüyor.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.