42 votes

Est-il possible de scinder des chaînes avec String.split () et d'inclure les délimiteurs?

J'essaie de scinder une chaîne avec tous les caractères non alphanumériques en tant que délimiteurs, mais la méthode String.split () de Java supprime les caractères de délimitation du tableau résultant. Est-il possible de fractionner une chaîne comme le fait le modèle regex "\ W", tout en conservant les délimiteurs?

75voto

polygenelubricants Points 136838

Vous souhaitez utiliser lookarounds, et split sur le zéro de la largeur des matchs. Voici quelques exemples:

public class SplitNDump {
    static void dump(String[] arr) {
        for (String s : arr) {
            System.out.format("[%s]", s);
        }
        System.out.println();
    }
    public static void main(String[] args) {
        dump("1,234,567,890".split(","));
        // "[1][234][567][890]"
        dump("1,234,567,890".split("(?=,)"));   
        // "[1][,234][,567][,890]"
        dump("1,234,567,890".split("(?<=,)"));  
        // "[1,][234,][567,][890]"
        dump("1,234,567,890".split("(?<=,)|(?=,)"));
        // "[1][,][234][,][567][,][890]"

        dump(":a:bb::c:".split("(?=:)|(?<=:)"));
        // "[][:][a][:][bb][:][:][c][:]"
        dump(":a:bb::c:".split("(?=(?!^):)|(?<=:)"));
        // "[:][a][:][bb][:][:][c][:]"
        dump(":::a::::b  b::c:".split("(?=(?!^):)(?<!:)|(?!:)(?<=:)"));
        // "[:::][a][::::][b  b][::][c][:]"
        dump("a,bb:::c  d..e".split("(?!^)\\b"));
        // "[a][,][bb][:::][c][  ][d][..][e]"

        dump("ArrayIndexOutOfBoundsException".split("(?<=[a-z])(?=[A-Z])"));
        // "[Array][Index][Out][Of][Bounds][Exception]"
        dump("1234567890".split("(?<=\\G.{4})"));   
        // "[1234][5678][90]"

        // Split at the end of each run of letter
        dump("Boooyaaaah! Yippieeee!!".split("(?<=(?=(.)\\1(?!\\1))..)"));
        // "[Booo][yaaaa][h! Yipp][ieeee][!!]"
    }
}

Et oui, c'est triplement imbriquée affirmation il y a dans le dernier modèle.

Questions connexes

Voir aussi

23voto

Markus Jarderot Points 33893
 import java.util.regex.*;
import java.util.LinkedList;

public class Splitter {
    private static final Pattern DEFAULT_PATTERN = Pattern.compile("\\s+");

    private Pattern pattern;
    private boolean keep_delimiters;

    public Splitter(Pattern pattern, boolean keep_delimiters) {
        this.pattern = pattern;
        this.keep_delimiters = keep_delimiters;
    }
    public Splitter(String pattern, boolean keep_delimiters) {
        this(Pattern.compile(pattern==null?"":pattern), keep_delimiters);
    }
    public Splitter(Pattern pattern) { this(pattern, true); }
    public Splitter(String pattern) { this(pattern, true); }
    public Splitter(boolean keep_delimiters) { this(DEFAULT_PATTERN, keep_delimiters); }
    public Splitter() { this(DEFAULT_PATTERN); }

    public String[] split(String text) {
        if (text == null) {
            text = "";
        }

        int last_match = 0;
        LinkedList<String> splitted = new LinkedList<String>();

        Matcher m = this.pattern.matcher(text);

        while (m.find()) {

            splitted.add(text.substring(last_match,m.start()));

            if (this.keep_delimiters) {
                splitted.add(m.group());
            }

            last_match = m.end();
        }

        splitted.add(text.substring(last_match));

        return splitted.toArray(new String[splitted.size()]);
    }

    public static void main(String[] argv) {
        if (argv.length != 2) {
            System.err.println("Syntax: java Splitter <pattern> <text>");
            return;
        }

        Pattern pattern = null;
        try {
            pattern = Pattern.compile(argv[0]);
        }
        catch (PatternSyntaxException e) {
            System.err.println(e);
            return;
        }

        Splitter splitter = new Splitter(pattern);

        String text = argv[1];
        int counter = 1;
        for (String part : splitter.split(text)) {
            System.out.printf("Part %d: \"%s\"\n", counter++, part);
        }
    }
}

/*
    Example:
    > java Splitter "\W+" "Hello World!"
    Part 1: "Hello"
    Part 2: " "
    Part 3: "World"
    Part 4: "!"
    Part 5: ""
*/
 

Je n'aime pas vraiment l'inverse, où vous obtenez un élément vide à l'avant et à l'arrière. Un délimiteur n'est généralement ni au début ni à la fin de la chaîne, vous finissez donc le plus souvent par gaspiller deux bons emplacements de tableau.

Edit: cas limites fixes. La source commentée avec les cas de test peut être trouvée ici: http://snippets.dzone.com/posts/show/6453

11voto

Alan Moore Points 39365

Je suis arrivé en retard, mais le retour à la question initiale, pourquoi ne pas simplement utiliser lookarounds?

Pattern p = Pattern.compile("(?<=\\w)(?=\\W)|(?<=\\W)(?=\\w)");
System.out.println(Arrays.toString(p.split("'ab','cd','eg'")));
System.out.println(Arrays.toString(p.split("boo:and:foo")));

sortie:

[', ab, ',', cd, ',', eg, ']
[boo, :, and, :, foo]

EDIT: Ce que vous voyez ci-dessus est ce qui apparaît sur la ligne de commande lorsque j'exécute ce code, mais je vois maintenant que c'est un peu déroutant. Il est difficile de garder une trace de ce qui les virgules sont en partie le résultat et qui ont été ajoutés par l' Arrays.toString(). C'est DONC la coloration syntaxique n'aide pas non plus. Dans l'espoir d'obtenir la mise en évidence de travailler avec moi au lieu de contre moi, voici comment ces tableaux serait de le regarder j'ai été déclarer dans le code source:

{ "'", "ab", "','", "cd", "','", "eg", "'" }
{ "boo", ":", "and", ":", "foo" }

J'espère que c'est plus facile à lire. Merci pour le heads-up, @finnw.

10voto

anubhava Points 172509

Je sais que cette question est très ancienne et que sa réponse a également été acceptée. Mais je voudrais quand même soumettre une réponse très simple à la question initiale. Considérons ce code:

 String str = "Hello-World:How\nAre You&doing";
inputs = str.split("(?!^)\\b");
for (int i=0; i<inputs.length; i++) {
   System.out.println("a[" + i + "] = \"" + inputs[i] + '"');
}
 

SORTIE:

 a[0] = "Hello"
a[1] = "-"
a[2] = "World"
a[3] = ":"
a[4] = "How"
a[5] = "
"
a[6] = "Are"
a[7] = " "
a[8] = "You"
a[9] = "&"
a[10] = "doing"
 

J'utilise simplement la limite de mot \b pour délimiter les mots sauf lorsqu'il s'agit du début du texte.

9voto

cletus Points 276888

J'ai eu un coup d'oeil à l'réponses ci-dessus, et honnêtement, aucun d'entre eux je trouve satisfaisant. Ce que vous voulez faire est essentiellement imiter le Perl split fonctionnalité. Pourquoi Java ne permet pas ceci et ont une méthode join() quelque part au-delà de moi, mais je m'égare. Vous n'avez même pas besoin d'une classe pour cette vraiment. C'est juste une fonction. Exécuter cet exemple de programme:

Certaines réponses sont trop nuls-la vérification, que j'ai écrit récemment une réponse à une question ici:

http://stackoverflow.com/users/18393/cletus

De toute façon, le code:

public class Split {
    public static List<String> split(String s, String pattern) {
        assert s != null;
        assert pattern != null;
        return split(s, Pattern.compile(pattern));
    }

    public static List<String> split(String s, Pattern pattern) {
        assert s != null;
        assert pattern != null;
        Matcher m = pattern.matcher(s);
        List<String> ret = new ArrayList<String>();
        int start = 0;
        while (m.find()) {
            ret.add(s.substring(start, m.start()));
            ret.add(m.group());
            start = m.end();
        }
        ret.add(start >= s.length() ? "" : s.substring(start));
        return ret;
    }

    private static void testSplit(String s, String pattern) {
        System.out.printf("Splitting '%s' with pattern '%s'%n", s, pattern);
        List<String> tokens = split(s, pattern);
        System.out.printf("Found %d matches%n", tokens.size());
        int i = 0;
        for (String token : tokens) {
            System.out.printf("  %d/%d: '%s'%n", ++i, tokens.size(), token);
        }
        System.out.println();
    }

    public static void main(String args[]) {
        testSplit("abcdefghij", "z"); // "abcdefghij"
        testSplit("abcdefghij", "f"); // "abcde", "f", "ghi"
        testSplit("abcdefghij", "j"); // "abcdefghi", "j", ""
        testSplit("abcdefghij", "a"); // "", "a", "bcdefghij"
        testSplit("abcdefghij", "[bdfh]"); // "a", "b", "c", "d", "e", "f", "g", "h", "ij"
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X