2010-10-29 8 views
1

Je sais, je sais, maintenant j'ai deux problèmes 'n tout cela, mais regex signifie ici que je n'ai pas besoin d'écrire deux boucles compliquées. Au lieu de cela, j'ai une regex que seulement je comprends, et je serai employé pour yonks.Java replaceAll() & split() irrégularités

J'ai une chaîne, par exemple stack.overflow.questions[0].answer[1].postDate, et j'ai besoin d'obtenir le [0] et le [1], de préférence dans un tableau. "Facile!" mes neurones s'exclamé, il suffit d'utiliser regex et la méthode split sur votre chaîne d'entrée; donc je suis venu avec ceci:

String[] tokens = input.split("[^\\[\\d\\]]"); 

qui a produit les éléments suivants:

[, , , , , , , , , , , , , , , , [0], , , , , , , [1]] 

cher Oh. Donc, je pensais, "ce qui replaceAll faire dans ce cas?":

String onlyArrayIndexes = input.replaceAll("[^\\[\\d\\]]", ""); 

qui a produit:

[0][1] 

Hmm. Pourquoi ça? Je cherche un tableau de chaînes de deux éléments qui contient "[0]" comme premier élément et "[1]" comme le second. Pourquoi split ne fonctionne pas ici, quand les Javadocs déclarent qu'ils utilisent tous les deux la classe Pattern selon le Javadoc?

Pour résumer, j'ai deux questions: pourquoi le produit d'appel split() que grand tableau avec des espaces apparemment aléatoires et suis-je raison de penser le replaceAll fonctionne parce que l'expression rationnelle remplace tous les caractères qui ne correspondent pas « [ », un nombre et "]"? Qu'est-ce qui me manque, cela signifie que je m'attends à ce qu'ils produisent une sortie similaire (OK, c'est trois, et s'il vous plaît ne répondez pas "un indice?" À celui-ci!).

Répondre

4

bien de ce que je peux voir le split fonctionne, il vous donne un tableau qui contient la chaîne divisée pour chaque correspondance qui n'est pas un ensemble de parenthèses avec un chiffre au milieu.

comme pour le replaceAll Je pense que votre hypothèse est bonne. il supprime tout (remplacer le match par "") ce n'est pas ce que vous voulez.

De l'API documentation:

Splits cette chaîne autour des matches de l'expression régulière.

Cette méthode fonctionne comme si en invoquant le procédé à deux arguments scission avec l'expression donnée et un argument de limite de zéro.Les chaînes vides à la fin sont et ne sont donc pas incluses dans le tableau résultant .

La chaîne "boo: et: foo", par exemple, donne les résultats suivants avec ces expressions:

Regex  Result 
:  { "boo", "and", "foo" } 
o  { "b", "", ":and:f" } 
+0

Merci, c'est le fait que split me donne un élément dans le tableau pour chaque match de mon regex; c'est ce que je ne comprenais pas! –

2

Ce n'est pas une réponse directe à votre question, mais je veux vous montrer une API qui répondra à vos besoins.

Découvrez Splitter à partir de Google Goyave.

Donc, pour votre exemple, vous l'utiliser comme ceci:

Iterable<String> tokens = Splitter.onPattern("[^\\[\\d\\]]").omitEmptyStrings().trimResults().split(input); 

//Now you get back an Iterable which you can iterate over. Much better than an Array. 
for(String s : tokens) { 
    System.out.println(s); 
} 

Cette impression:
0
1

+0

Une excellente suggestion, merci. À l'heure actuelle, je n'ai d'utilisation que pour regex dans ce cas particulier, mais je vais aller à Guava au cas où j'en aurais besoin. –

+0

Google Guava prend en charge regex. Comme je l'ai montré dans l'exemple. –

2

split grand écart sur limites définies par l'expression rationnelle que vous fournissez, donc ce n'est pas une grande surprise que vous receviez beaucoup d'entrées   — presque tous les caractères de la chaîne correspondent à votre expression régulière et, par définition, sont des limites sur lesquelles une scission devrait se produire.

replaceAllremplace résultats correspondant à votre regex avec le remplacement que vous lui donnez, ce qui dans votre cas est une chaîne vide.

Si vous essayez de saisir le 0 et le 1, il est une boucle trivial:

String text = "stack.overflow.questions[0].answer[1].postDate"; 
Pattern pat = Pattern.compile("\\[(\\d+)\\]"); 
Matcher m = pat.matcher(text); 
List<String> results = new ArrayList<String>(); 
while (m.find()) { 
    results.add(m.group(1)); // Or just .group() if you want the [] as well 
} 
String[] tokens = results.toArray(new String[0]); 

Ou si elle est toujours exactement deux d'entre eux:

String text = "stack.overflow.questions[0].answer[1].postDate"; 
Pattern pat = Pattern.compile(".*\\[(\\d+)\\].*\\[(\\d+)\\].*"); 
Matcher m = pat.matcher(text); 
m.find(); 
String[] tokens = new String[2]; 
tokens[0] = m.group(1); 
tokens[1] = m.group(2); 
1

Le problème est que split est la mauvaise opération ici.

En ruby, je vous dis de string.scan(/\[\d+\]/), qui vous donnera le tableau ["[0]","[1]"]

Java ne dispose pas d'un équivalent unique méthode, mais nous pouvons écrire une méthode scan comme suit:

public List<String> scan(String string, String regex){ 
    List<String> list = new ArrayList<String>(); 
    Pattern pattern = Pattern.compile(regex); 
    Matcher matcher = pattern.matcher(string); 
    while(matcher.find()) { 
     list.add(matcher.group()); 
    } 
    return retval; 
} 

et nous pouvons l'appeler comme scan(string,"\\[\\d+\\]")

L'équivalent du code Scala est:

"""\[\d+\]""".r findAllIn string 
+0

Une approche intéressante; Merci! –