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?
Réponses
Trop de publicités?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
- Java split est de manger de mes personnages.
- Pouvez-vous utiliser de largeur nulle mise en correspondance dans la Chaîne de split?
- Comment puis-je convertir des CamelCase dans les noms lisibles en Java?
- Références arrières dans lookbehind
Voir aussi
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
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.
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.
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"
}
}