Frage zu regulären Ausdrücken

Studdi23

Mitglied
Hallo zusammen,

ich kämpfe gerade mit einer RegEx und brauche dringend Hilfe. Und zwar habe ich folgenden Ausdruck zusammengebastelt

Java:
String REGEX = "(?<!(\\\\)\'.{0,200}(?<!\\\\)\'";

Das Pattern matcht alles was mit einem Hochkomma beginnt und endet. Die Zeichen dazwischen sind egal.Es darf aber kein Backslash vor einem Hochkomma stehen, was ich mit einem Lookbehind gelöst habe. Mein Problem ist das ich zwischen den Hochkommata eine gerade Anzahl an Backslashes zulassen will. Z.B. sind '\\\\' und '\\' erlaubt aber nicht '\\\' oder '\'. Ich weiß das man Backreferences für Wiederholungen verwenden kann, weiß allerdings nicht wie ich sie anwenden soll, vor allem in Kombination mit Lookbehinds/Lookaheads. Jemand eine Idee?

Gruß
Mario
 
Ich find' den http://reb4j.sourceforge.net/ ja praktisch (wenn man schon meint, sowas unbedingt mit RegEx machen zu müssen...)

Java:
import java.util.regex.Pattern;

import net.sourceforge.reb4j.CharClass;
import net.sourceforge.reb4j.Regex;

public class RegexTest0001
{
    public static void main(String[] args)
    {
        final Regex apostrophe = CharClass.range('\'', '\'');
        final Regex backslash = CharClass.range('\\', '\\');
        final Regex doubleBackslash = backslash.then(backslash);
        final Regex noBackslash = CharClass.characters("\\", true);
        final Regex other = noBackslash.or(doubleBackslash);
        final Regex result = apostrophe.then(other.star()).then(apostrophe);
        final Pattern pattern = result.toPattern();
        System.out.println(pattern);
        test(pattern, "'a test'", true);
        test(pattern, "'a \\ test'", false);
        test(pattern, "'a \\\\ test'", true);
        test(pattern, "'a test\\'", false);
        test(pattern, "'a test\\\\'", true);
    }
    
    private static void test(Pattern pattern, String string, boolean expected)
    {
        boolean valid = pattern.matcher(string).matches();
        System.out.println(
            String.format("%5s", String.valueOf(valid))+" (expected "+
            String.format("%5s", String.valueOf(expected))+") for "+string);
    }
}


->

Code:
(?:(?:['-'](?:(?:[^\\]|(?:[\\-\\][\\-\\]))*))['-'])
 true (expected  true) for 'a test'
false (expected false) for 'a \ test'
 true (expected  true) for 'a \\ test'
false (expected false) for 'a test\'
 true (expected  true) for 'a test\\'

Wobei der letzte Fall eben fragwürdig ist - eigentlich steht dort ein \ vor dem Hochkomma, aber das wird dadurch nicht escapt... Kann man aber bestimmt auch noch hinfrickeln, falls das nicht matchen soll....
 
Ich würde das wie folgt lösen:
Java:
String regex="(?<!\\\\)\'(?:[^\\\\]|\\\\\\\\){0,200}\'";

Aber was soll eigentlich passieren wenn als Input z.b. "\\\\'test'" ankommt? Mit einem Lookbehind kann man aber leider keine variablen Längen überprüfen um gezielt sicherstellen zu können das keine ungerade Anzahl von Backslashes vor dem ersten ' ist.
 
Danke euch beiden erstmal für die Antwort.

@Marco
Nein das ist schon richtig so. Der erste Backslash maskiert den Zweiten, dadurch stehen alle Zeichen korrekt zwischen zwei Hochkommata.

Wenn ich richtig verstanden habe, erstellst du dir mit Hilfe der Bibliothek deine RegEx und toResult erzeugt daraus das Pattern. Nun würde ich gerne auf die Lib verzichten und das generierte Pattern direkt verwenden, bekomme allerdings folgende Exception:
"Unclosed character class near index 45 (?🙁?:['-'](?🙁?:[^\]|(?:[\-\][\-\]))*))['-'])"

Habe ich im Ausdruck etwas vergessen oder ist dieser nicht für eine direkte Verwendung vorgesehen?

@Lumaraf
Das wäre kein Problem, da nach dem Zerlegen eine Syntax-Prüfung aller Tokens stattfindet und Backslashes an dieser Stelle mit einer Fehlermeldung behandelt werden würden.



@all
Neue Frage: Beispielsweise ich habe zwei Strings im Input: 'erster String' irgendwas 'zweiter String'
In diesem Fall matcht er 3 Strings. ' irgendwas ' wird auch als String erkannt, er soll aber das String' als End-String erkennen und 'zweiter als Start-String. Ist das mit RegEx möglich?

Gruß
Mario
 
Zuletzt bearbeitet:
ich stand gerade vor selben problem zum Einlesen einer gewissen Regelmenge .. da ich früher schon viel damit rumgespielt habe bin ich diesmal gleich zur manuellen Variante übergegangen 😀

Beispieleingabe: 'foo \\\' bar\'' ['feebee' $2 'foo'] 'boo\''
content nach Bearbeitung: foo \' bar'

Java:
//--------------------------------------------------
// string starts with ' and is new string
sb.deleteCharAt(0);

//search corresponding end character
int indexOfEndChar = sb.indexOf(String.valueOf(ENCLOSE_EQUIV_STRING));
while (isEscaped(sb, 0,indexOfEndChar-1)) { //da wirds getestet
	//delete escaping character
	sb.deleteCharAt(indexOfEndChar-1);
	indexOfEndChar = sb.indexOf(String.valueOf(ENCLOSE_EQUIV_STRING), indexOfEndChar);
}//while
			
if (indexOfEndChar < 0) {
	throw new ReadSyntaxMappingFileException("Missing \"" + ENCLOSE_EQUIV_STRING + "\".");
} else {
	content = sb.substring(0, indexOfEndChar);
	//remove content and corresponding enclosing char at end
	sb.delete(0, content.length()+1);
}//if
		
//replace escaping sequences with correct number of chars
return new ExtendedSingleEquivInfo(isReference, content.replaceAll("\\\\\\\\", "\\\\"));
//--------------------------------------------------

private static boolean isEscaped(StringBuilder sb, int startIndex, int endIndex) {
		if (endIndex < startIndex)
			return false;
			
		int quantityOfEscapeChars = 0;
		
		//check from end to start and break if any non escape-char has been found
		for(int i=endIndex; i>=startIndex; i--) {
			if (sb.charAt(i) == ESCAPE_CHAR) {
				quantityOfEscapeChars++;
			} else {
				break;
			}//if
		}//for

		//uneven quantity => is escaped
		return ((quantityOfEscapeChars % 2) != 0);
	}//isEscaped
 
Zuletzt bearbeitet:
Nun würde ich gerne auf die Lib verzichten und das generierte Pattern direkt verwenden, bekomme allerdings folgende Exception:
"Unclosed character class near index 45 (?🙁?:['-'](?🙁?:[^\]|(?:[\-\][\-\]))*))['-'])"

Kein Grund gleich so viele traurige Smileys zu posten 😀 Die Doppelten \\ müssen zu vierfachen \\\\ werden - warum, solltest du dir in Anbetracht der ursprünglichen Frage eigentlich denken können 😉

Java:
import java.util.regex.Pattern;

public class RegexTest
{
	public static void main(String[] args)
	{
		final Pattern pattern = Pattern.compile("(?:(?:['-'](?:(?:[^\\\\]|(?:[\\\\-\\\\][\\\\-\\\\]))*))['-'])");
		
		System.out.println(pattern);
		test(pattern, "'a test'", true);
		test(pattern, "'a \\ test'", false);
		test(pattern, "'a \\\\ test'", true);
		test(pattern, "'a test\\'", false);
		test(pattern, "'a test\\\\'", true);
	}

	private static void test(Pattern pattern, String string, boolean expected)
	{
		boolean valid = pattern.matcher(string).matches();
		System.out.println(String.format("%5s", String.valueOf(valid)) + " (expected "
				+ String.format("%5s", String.valueOf(expected)) + ") for " + string);
	}
}
 
@marco
Super! Vielen herzlichen Dank. Und hierfür noch nen lachenden Smiley 😀

@digga
Sieht vielversprechend aus, ich bevorzuge aber die kürzere Variante. Nichts für ungut 🙂

Gruß
Mario
 

Neue Themen


Zurück
Oben