2009-06-25 7 views
0

Essaye d'extraire les chaînes qui sont enveloppées dans des doubles parenthèses. Par exemple [[ceci est un jeton]] qui devrait correspondre. Pour rendre les choses plus élégantes, il devrait y avoir une séquence d'échappement afin que les éléments entre crochets comme \ [[ce jeton d'échappement \]] ne soient pas appariés.RegEx en Java ne fonctionne pas comme prévu

Le motif [^\\\\]([\\[]{2}.+[^\\\\][\\]]{2}) avec le "groupe 1" pour extraire le jeton est proche, mais il y a des situations où cela ne fonctionne pas. Le problème semble être que la première déclaration "non" est évaluée comme "n'importe quoi sauf une barre oblique inverse". Le problème est que "n'importe quoi" n'inclut pas "rien". Alors, qu'est-ce qui ferait correspondre ce motif à "rien ou n'importe quel caractère autre qu'un antislash"?

Voici un test unitaire pour montrer le comportement souhaité:

import java.util.regex.Matcher; 
import java.util.regex.Pattern; 
import junit.framework.TestCase; 

public class RegexSpike extends TestCase { 
    private String regex; 
    private Pattern pattern; 
    private Matcher matcher; 

    @Override 
    protected void setUp() throws Exception { 
     super.setUp(); 
     regex = "[^\\\\]([\\[]{2}.+[^\\\\][\\]]{2})"; 
     pattern = Pattern.compile(regex); 
    } 

    private String runRegex(String testString) { 
     matcher = pattern.matcher(testString); 
     return matcher.find() ? matcher.group(1) : "NOT FOUND"; 
    } 

    public void testBeginsWithTag_Passes() { 
     assertEquals("[[should work]]", runRegex("[[should work]]")); 
    } 

    public void testBeginsWithSpaces_Passes() { 
     assertEquals("[[should work]]", runRegex(" [[should work]]")); 
    } 

    public void testBeginsWithChars_Passes() { 
     assertEquals("[[should work]]", runRegex("anything here[[should 
work]]")); 
    } 

    public void testEndsWithChars_Passes() { 
     assertEquals("[[should work]]", runRegex("[[should 
work]]with anything here")); 
    } 

    public void testBeginsAndEndsWithChars_Passes() { 
     assertEquals("[[should work]]", runRegex("anything here[[should 
work]]and anything here")); 
    } 

    public void testFirstBracketsEscaped_Fails() { 
     assertEquals("NOT FOUND", runRegex("\\[[should NOT work]]")); 
    } 

    public void testSingleBrackets_Fails() { 
     assertEquals("NOT FOUND", runRegex("[should NOT work]")); 
    } 

    public void testSecondBracketsEscaped_Fails() { 
     assertEquals("NOT FOUND", runRegex("[[should NOT work\\]]")); 
    } 

} 
+0

ne signifie rien NULL ou des espaces? – northpole

Répondre

3

Vous pouvez simplement utiliser (^|[^\\]), qui sera soit correspondance le début d'une chaîne (à condition que vous définissez le mode MULTILINE sur votre regex) ou un seul caractère qui n'est pas une barre oblique inverse (y compris les espaces, nouvelles lignes, etc.).

Vous aurez également remplacer .+ avec .+?, car sinon une chaîne telle que "[[one]] and [[two]]" sera considérée comme une seule, où "one]] and [[two" est considéré comme entre parenthèses.

Un troisième point est que vous ne devez pas envelopper un seul caractère (même les échappées telles que \[ ou \]) dans une classe de caractères avec [].

Alors que ferait l'expression rationnelle suivante (pardonnez-moi de retirer le double escapedness pour plus de clarté).

(^|[^\\])(\[{2}.+?[^\\]\]{2}) 

(Notez également que vous ne pouvez pas échapper au caractère d'échappement avec votre regex Deux barres obliques avant un [ ne sera pas analysé comme une barre oblique unique (échappée), mais indiquera une barre oblique unique (non échappée) et une parenthèse échappée.)

1

Vous voulez une « affirmation négative lookbehind zéro largeur », qui est (?<!expr). Essayez:

(?<!\\\\)([\\[]{2}.+[^\\\\][\\]]{2}) 

En fait, cela peut être simplifié et rendu plus général en coupant certaines de ces crochets inutiles, et en ajoutant un lookbehind négatif pour le support de fermeture, aussi. (Votre version échouera également si vous avez une parenthèse échappée au milieu de la chaîne, comme [[text\]]moretext]]).

(?<!\\\\)(\\[{2}.*?(?<!\\\\)\\]{2}) 
1

Que devrait-il se passer avec cette chaîne? (Teneur en chaîne réelle, pas un Java littéral.)

foo\\[[blah]]bar 

Ce que je vous demande est de savoir si vous soutenez évadé antislashs. Si vous êtes, le lookbehind ne fonctionnera pas. Au lieu de rechercher une seule barre oblique inverse, vous devrez vérifier sur un nombre impair mais inconnu, et Java lookbehinds ne peut pas être ouvert comme ça. En outre, qu'en est-il des parenthèses échappées à l'intérieur un jeton - est-ce valide?

foo[[blah\]]]bar 

Dans tous les cas, je vous suggère de venir au problème de la barre oblique inverse de l'autre direction: faire correspondre un nombre quelconque de caractères (à savoir échappées backslash quoi que ce soit), plus précédant immédiatement la première tranche dans le cadre du jeton. À l'intérieur du jeton, faites correspondre n'importe quel nombre de caractères autres que les crochets ou les barres obliques inverses, ou n'importe quel nombre de caractères échappés. Voici la regex:

(?<!\\)(?:\\.)*+\[\[((?:[^\[\]\\]++|\\.)*+)\]\] 

... et voilà comme une chaîne Java littérale:

"(?<!\\\\)(?:\\\\.)*+\\[\\[((?:[^\\[\\]\\\\]++|\\\\.)*+)\\]\\]" 
Questions connexes