2011-11-24 6 views
26

Dato un elencoIscrizione a un elenco <String> in Java con virgole e "e"

List<String> l = new ArrayList<String>(); 
l.add("one"); 
l.add("two"); 
l.add("three"); 

Ho un metodo

String join(List<String> messages) { 
     if (messages.isEmpty()) return ""; 
     if (messages.size() == 1) return messages.get(0); 
     String message = ""; 
     message = StringUtils.join(messages.subList(0, messages.size() -2), ", "); 
     message = message + (messages.size() > 2 ? ", " : "") + StringUtils.join(messages.subList(messages.size() -2, messages.size()), ", and "); 
     return message; 
    } 

che, per l, produce "uno, due e tre" . La mia domanda è: esiste un metodo standard (apache-commons), che fa la stessa cosa ?, per esempio

WhatEverUtils.join(l, ", ", ", and "); 

Per chiarire. Il mio problema non è quello di far funzionare questo metodo. Funziona esattamente come lo voglio io, è testato e va tutto bene. Il mio problema è che non sono riuscito a trovare alcun modulo apache-commons-like che implementa tale funzionalità. Il che mi sorprende, dal momento che non posso essere il primo a aver bisogno di questo.

Ma allora forse tutti gli altri hanno appena fatto

StringUtils.join(l, ", ").replaceAll(lastCommaRegex, ", and"); 
+0

Non penso che ci sia una tale libreria open source, ma consiglio di usare un pacchetto di risorse poiché non tutte le lingue usano la parola inglese "and". –

+0

@slipset, perché non usi un po 'di join dalla libreria conosciuta e lo modifichi un po'? Si noti che "e" è una parola inglese, quindi se tale libreria esistesse, doveva avere il supporto di più lingue – smas

+0

Forse non sono stato chiaro, ma ho scritto il metodo che mostro nella mia domanda e funziona esattamente come voglio. – slipset

risposta

13

Mi piace usare le collezioni di Google per questo scopo. Neat e molto utile:

Joiner.on(",").join(myList) 

Questo tipo di codice è stato scritto più volte e si dovrebbe piuttosto essere liberati attuare la logica specifica implementazione.

Se si utilizza Maven, con la presente la dipendenza:

<dependency> 
    <groupId>com.google.collections</groupId> 
    <artifactId>google-collections</artifactId> 
    <version>1.0</version> 
</dependency> 

E 'un sacco di altre caratteristiche fredde meravigliosa troppo!

MODIFICA: Per motivi di completezza, questo produrrà la lista "uno, due e tre".

List<String> originalList = Arrays.asList("one", "two", "three"); 
Joiner.on(", ").join(originalList.subList(0, originalList.size() - 1)) 
    .concat(", and ").concat(originalList.get(originalList.size() - 1)); 
+2

Solo per FYI: le raccolte di google sono state ritirate a favore di Guava (http://code.google.com/p/guava-libraries/) che è un superset completamente compatibile con le versioni precedenti. –

+0

Abbastanza corretto .. me ne sono dimenticato. La dipendenza Maven se qualcuno è interessato: com.google.guava guava 10.0.1

+1

non vedo il motivo per cui si sta downvoting risposte con il metodo che producono registrazione: "uno , due tre". È così difficile sostituire l'ultima virgola con qualsiasi stringa tu voglia, o qualcosa di simile ?! Questa è una risposta OK al 100% che dà a @slipset la possibile direzione che può risolvere il suo problema. – smas

1

Io non conosco nessun falegname Apache String in grado di supportare l'aggiunta and nella stringa unito.

Ecco un codice non testato che farà quello che hai chiesto:

public static String join(String separator, List<String> mList, boolean includeAndInText) { 
    StringBuilder sb = new StringBuilder(); 
    int count = 0; 

    for (String m: mList) { 
     if (includeAndInText && (count + 1 != mList.size())) { 
      sb.append (" and "); 
     } 

     sb.append(m); 
     count++; 
     if (count < mList.size()) { 
      sp.append(separator); 
     }  
    } 

    return sb.toString(); 
} 
+0

scusate, ma non penso che questo sia l'approccio migliore a questo problema. IMO dovremmo usare qualcosa che esiste (ad esempio join da Apache) e modificarlo un po 'per ottenere "e", "o" o qualcosa che ci aspettiamo di avere. – smas

+0

@smas, ok, non sono d'accordo. La modifica di una libreria esistente per conformarsi al tuo ** solo ** requisito non è una scelta ovvia dato che (e non credo) ti impegnerai a passare ad Apache. Inoltre, se viene rilasciata un'altra versione di 'StringUtils', dovrai mantenerla e assicurarti che la tua modifica non sia influenzata (cancellata).Dico, lascia l'implementazione della libreria AS-IS e scrivi la tua classe di Utility. –

+1

I diagree anche. Nel mondo degli affari sono molto usate librerie note come StringUtils per evitare di reinventare la ruota. Se sei a conoscenza di alcune modifiche, scrivi i test unitari. Per questo caso la scrittura si unisce solo perché "e" deve esserci spreco di tempo, denaro e stile di programmazione orientata agli oggetti. – smas

11

Che dire join da: org.apache.commons.lang.StringUtils

Esempio:

StringUtils.join(new String[] { "one", "two", "three" }, ", "); // one, two, three 

di avere "e" o", e "puoi semplicemente sostituire l'ultima virgola.

+0

Questo non produce '" uno, due e tre "' come richiesto dall'OP. Osserva: sta usando il metodo 'join' nella sua domanda –

+0

@Lukas, ma puoi sostituire l'ultima virgola, giusto? Non ho senso avere una libreria che aggiunga per me questo "e" nel metodo di join. – smas

+0

FYI - Ho sollevato https://issues.apache.org/jira/browse/LANG-1037 per richiedere l'inclusione di ulteriori metodi per farlo. Proverò a implementarlo nella prossima versione. –

3

Altre risposte parlano di "sostituzione dell'ultima virgola", che non è sicuro se l'ultimo termine contiene una virgola.

Invece di usare una libreria, si può semplicemente utilizzare una (seppur lunga) riga di codice JDK:

public static String join(List<String> msgs) { 
    return msgs == null || msgs.size() == 0 ? "" : msgs.size() == 1 ? msgs.get(0) : msgs.subList(0, msgs.size() - 1).toString().replaceAll("^.|.$", "") + " and " + msgs.get(msgs.size() - 1); 
} 

Consulta l'live demo di questa gestione di tutti i casi limite di codice.


Cordiali saluti, ecco una più leggibile due-liner:

public static String join(List<String> msgs) { 
    int size = msgs == null ? 0 : msgs.size(); 
    return size == 0 ? "" : size == 1 ? msgs.get(0) : msgs.subList(0, --size).toString().replaceAll("^.|.$", "") + " and " + msgs.get(size); 
} 
7

con Java 8, è possibile utilizzare i flussi con falegnami.

Collection<String> strings; 
... 
String commaDelimited = strings.stream().collect(Collectors.joining(",")); 
// use strings.parallelStream() instead, if you think 
// there are gains to be had by doing fork/join 
21

In Java 8 è possibile utilizzare String.join() come segue:

Collection<String> elements = ....; 
String result = String.join(", ", elements); 
0

per produrre un output grammaticale in inglese ci sono 3 casi da considerare quando si concatenare un elenco di stringhe:

  1. "A"

  2. "A e B"

  3. "A, B, e C.

Ciò può essere realizzato utilizzando standard di Java o Guava come qui di seguito. Le soluzioni sono fondamentalmente le stesse e preferiscono solo ciò che si desidera utilizzare.

import com.google.common.base.Joiner; 
import com.google.common.collect.ImmutableList; 

import org.junit.Test; 

import java.util.List; 

import static org.junit.Assert.assertEquals; 

public class JoinListTest { 

    @Test 
    public void test_join() { 
     // create cases (don't need to use ImmutableList builder from guava) 
     final List<String> case1 = new ImmutableList.Builder<String>().add("A").build(); 
     final List<String> case2 = new ImmutableList.Builder<String>().add("A", "B").build(); 
     final List<String> case3 = new ImmutableList.Builder<String>().add("A", "B", "C").build(); 
     // test with standard java 
     assertEquals("A", joinListGrammaticallyWithJava(case1)); 
     assertEquals("A and B", joinListGrammaticallyWithJava(case2)); 
     assertEquals("A, B, and C", joinListGrammaticallyWithJava(case3)); 
     // test with guava 
     assertEquals("A", joinListGrammaticallyWithGuava(case1)); 
     assertEquals("A and B", joinListGrammaticallyWithGuava(case2)); 
     assertEquals("A, B, and C", joinListGrammaticallyWithGuava(case3)); 
    } 

    private String joinListGrammaticallyWithJava(final List<String> list) { 
     return list.size() > 1 
       ? String.join(", ", list.subList(0, list.size() - 1)) 
        .concat(String.format("%s and ", list.size() > 2 ? "," : "")) 
        .concat(list.get(list.size() - 1)) 
       : list.get(0); 
    } 

    private String joinListGrammaticallyWithGuava(final List<String> list) { 
     return list.size() > 1 
       ? Joiner.on(", ").join(list.subList(0, list.size() - 1)) 
        .concat(String.format("%s and ", list.size() > 2 ? "," : "")) 
        .concat(list.get(list.size() - 1)) 
       : list.get(0); 
    } 

} 
Problemi correlati