reguläre Ausdrücke finden nicht was sie finden sollen

Curry

Aktives Mitglied
Moin Moin!

Ich habe zwei Probleme mit reguläre Ausdrücken.

1)
Ich möchte die Anzeige meiner Tabelle anhand eines Namens in einem Feld filtern. Der Inhalt des Feldes schaut z.B. so aus "Müller P, Stolz KW, Nolte K, Schmidt HG, Mayer F".

Ich möchte das Einträge auch gefunden werden wenn der Name noch nicht vollständig geschrieben wurde (aber beim Anfang des Namens muss begonnen werden) und es soll möglich sein nach mehreren Namen gleichzeitig (am besten mit einer und / oder Möglichkeit, z.B. durch Eingabe von "|" oder "+") zu Suchen.

Der zu suchende Namen wird in ein JTextField eingegeben. Das obere Beispiel soll z.B. gefunden werden bei der Eingabe von "S", "Sto", "Stolz KW" oder "KW". Aktuell verwende ich den folgenden Code:

Java:
RowFilter<MyTableModel, Integer> authorFilter = new RowFilter<MyTableModel, Integer>() {
	public boolean include(Entry<? extends MyTableModel, ? extends Integer> entry) {
		MyTableModel tableModel = entry.getModel();
		Paper paper = tableModel.getPaper(entry.getIdentifier());

		String regex = "(?i)[\\w]*(" + model.getFilter(FILTER_AUTHOR) + ")[\\w]*";
		
		System.out.println(paper.getAuthorList() + " => " + regex);
		
		if (paper.getAuthorList().matches(regex)) {
				return true;
		}
		return false;
	}
};

2)
Bei meinem zweiten Problem möchte ich gerne Teile eines Textes, der in einem JEditorPane angezeigt wird, rot hervorheben, wenn diese in einem JTextField eingetragen wurden. Doch auch dies funktioniert leider nicht so wie ich es versuche. Derzeit schaut der Code so aus:

Java:
String str = tableModel.getPaper(rowIndex).getText();
String filter = model.getFilter(FILTER_ABSTRACT);
if(filter.length() > 0) {
	System.out.println("filter -> " + filter);
	str.replaceAll("(" + filter + ")", "<span style=\"color: #FF0000;\">" + filter + "</span>");
}
String text = "<p style=\"margin: 0px 0px 5px 0px; text-align: justify;\">" + str + "</p>";

Würde mich sehr über Hilfe und Tipps freuen!!
 
Auf den ersten Blick seh ich jetzt nichts.
Falls du mit Eclipse arbeitest, hast du dir das QuickRex-Plugin installiert?
Damit kannst du RegEx ausprobieren, und siehst sofort ob es funktioniert.
 
Ah.

1. Problem:
Ich denke das Problem liegt in:
Java:
getAuthorList().matches()

2. Problem:
Schreibe
Java:
str = str.replaceAll("(" + filter + ")", "<span style=\"color: #FF0000;\">" + filter + "</span>");
 
zum 2. Problem:
Danke, JPT, das war natürlich das Problem ... wer die API Specification lesen kann ist klar im Vorteil. ;-)

bezüglich des 1. Problems:
Ich verwende "The Regex Coach" zum Testen und dort markiert er mir die Teile Namensliste richtig. Allerdings erfüllt der RegEx auch dort noch nicht das Kriterium, dass das keine Zeichenkombinationen inmitten eines Namens gefunden werden sollen.

Ich probiere aber mal, ob ich das nicht ohne einen RegEx hinbekomme (split, for-Schleife, toLowerCase, startsWith). Allerdings stelle ich mir die Frage nach der Performance. Wie schaut's aus wenn ich da mehrere 100 Zeilen in der Tabelle habe?
 
Wenn du jeden Datensatz in einem eigenen Objekt verwaltest, dass hast du gleich viel weniger Probleme. Splitte die Namen mit
Code:
split
und such dann den String mit
Code:
contains
. Falls du gleich noch die Position des gefundenen Substrings brauchst reicht auch
Code:
indexOf
.

Keine Ahnung was du hier mit Regex willst. Es gilt doch: Wenn du ein Problem hast und es mit Regex lösen willst, dann hast du zwei Probleme.

Performance sollte bei ein paar hundert Datensätzen noch keine Probleme machen.
 
bezüglich des 1. Problems:
Ich verwende "The Regex Coach" zum Testen und dort markiert er mir die Teile Namensliste richtig. Allerdings erfüllt der RegEx auch dort noch nicht das Kriterium, dass das keine Zeichenkombinationen inmitten eines Namens gefunden werden sollen.
Davon ausgehend, dass alle Namen immer mit Kommas voneinander getrennt sind, sollte der folgende reguläre Ausdruck das verlangte Kriterium erfüllen:
Code:
(?i)([^,]*\b<Hier Suchstring einfügen>[^,]*)
Hier mal ein kurzes, kompilierbares (evtl. noch unausgereiftes) Beispiel mit eben diesem regulären Ausdruck im Einsatz:
Java:
public class Namesearcher
{
	public static void main(String[] args)
	{
		JFrame frame = new JFrame("Namesearcher");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		final JTextField searchField = new JTextField();
		final JTextField dataField = new JTextField();
		final JTextField resultField = new JTextField();
		searchField.setDocument(new CertainCharactersDocument("[^\\p{Alpha}ÄÖÜäöüß -]"));
		dataField.setDocument(new CertainCharactersDocument("[^\\p{Alpha}ÄÖÜäöüß, -]"));
		DocumentListener docListener = new DocumentListener()
		{
			@Override
			public void removeUpdate(DocumentEvent e)
			{
				search();
			}
			
			@Override
			public void insertUpdate(DocumentEvent e)
			{
				search();
			}
			
			@Override
			public void changedUpdate(DocumentEvent e)
			{
				// empty
			}
			
			private void search()
			{
				String searchString = searchField.getText();
				if(searchString.isEmpty()) {
					resultField.setText("");
				} else {
					Pattern pattern = Pattern.compile("(?i)([^,]*\\b" + searchString + "[^,]*)");
					Matcher matcher = pattern.matcher(dataField.getText());
					StringBuilder str = new StringBuilder();
					while(matcher.find()) {
						str.append(matcher.group(1));
					}
					resultField.setText(str.toString());
				}
			}
		};
		searchField.getDocument().addDocumentListener(docListener);
		dataField.getDocument().addDocumentListener(docListener);
		dataField.setText("Müller P, Stolz KW, Nolte K, Schmidt HG, Mayer F");
		resultField.setEditable(false);
		
		Container container = frame.getContentPane();
		container.setLayout(new GridLayout(3, 2));
		container.add(new JLabel("Search for:"));
		container.add(searchField);
		container.add(new JLabel("Data:"));
		container.add(dataField);
		container.add(new JLabel("Result:"));
		container.add(resultField);
		
		frame.pack();
		frame.setVisible(true);
	}
}

class CertainCharactersDocument extends PlainDocument
{
	private static final long serialVersionUID = 8295705287949439607L;
	private String illegalCharactersRegex;
	
	public CertainCharactersDocument(String illegalCharactersRegex)
	{
		this.illegalCharactersRegex = illegalCharactersRegex;
	}
	
	@Override
	public void insertString(int offs, String str, AttributeSet a) throws BadLocationException
	{
		if(str.matches(illegalCharactersRegex)) {
			return;
		}
		super.insertString(offs, str, a);
	}
}
Zu suchenden Namen eingeben, im Datenfeld Namen hinzufügen / entfernen und Ergebnis betrachten. 😉
 
@Mizar: Das funktioniert sehr schön, doch fehlt die in meinem Startposting erwähnte "und/oder" Funktion. Aber das ist wahrscheinlich wirklich schwierig und deutlich aufwändiger. Auf jeden Fall schonmal vielen Dank. Das ist so schon richtig gut!
 
Ah, genau, die "und / oder" Funktion. Habe meinen Code entsprechend angepasst, um nun mittels des '+'-Zeichens das Suchen nach mehreren Namen gleichzeitig zu ermöglichen. Alle Änderungen sind mit Kommentaren versehen.
Java:
public class Namesearcher
{
    public static void main(String[] args)
    {
        JFrame frame = new JFrame("Namesearcher");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        final JTextField searchField = new JTextField();
        final JTextField dataField = new JTextField();
        final JTextField resultField = new JTextField();
        // Nicht vergessen: Das "+ Zeichen" (oder ein entsprechendes anderes Zeichen) im Suchfeld erlauben.
        searchField.setDocument(new CertainCharactersDocument("[^\\p{Alpha}ÄÖÜäöüß\\+ -]"));
        dataField.setDocument(new CertainCharactersDocument("[^\\p{Alpha}ÄÖÜäöüß, -]"));
        DocumentListener docListener = new DocumentListener()
        {
            @Override
            public void removeUpdate(DocumentEvent e)
            {
                search();
            }
            
            @Override
            public void insertUpdate(DocumentEvent e)
            {
                search();
            }
            
            @Override
            public void changedUpdate(DocumentEvent e)
            {
                // empty
            }
            
            private void search()
            {
                String searchString = searchField.getText().trim();
                if(searchString.isEmpty()) {
                    resultField.setText("");
                } else {
                	Pattern pattern;
                	Matcher matcher;
                	// HashSet um mehrfach gefundene Treffer zu ignorieren.
                	HashSet<String> results = new HashSet<String>();
                	// Jeden Teilsuchstring einzeln auf das Datenfeld loslassen.
                	String[] searchStrings = searchString.split("\\+");
                	for(String currentSearchString: searchStrings) {
                		currentSearchString = currentSearchString.trim();
                		if(!currentSearchString.isEmpty()) {
		                    pattern = Pattern.compile("(?i)([^,]*\\b" + currentSearchString + "[^,]*)");
		                    matcher = pattern.matcher(dataField.getText());
		                    while(matcher.find()) {
		                    	results.add(matcher.group(1));
		                    }
                		}
                	}
                	// Alle Ergebnisse zu einem String zusammenfügen und ins Ergebnisfeld schreiben.
                    StringBuilder str = new StringBuilder();
                    for(String s: results) {
                    	str.append(s);
                    }
                    resultField.setText(str.toString());
                }
            }
        };
        searchField.getDocument().addDocumentListener(docListener);
        dataField.getDocument().addDocumentListener(docListener);
        dataField.setText("Müller P, Stolz KW, Nolte K, Schmidt HG, Mayer F");
        resultField.setEditable(false);
        
        Container container = frame.getContentPane();
        container.setLayout(new GridLayout(3, 2));
        container.add(new JLabel("Search for:"));
        container.add(searchField);
        container.add(new JLabel("Data:"));
        container.add(dataField);
        container.add(new JLabel("Result:"));
        container.add(resultField);
        
        frame.pack();
        frame.setVisible(true);
    }
}
 
class CertainCharactersDocument extends PlainDocument
{
    private static final long serialVersionUID = 8295705287949439607L;
    private String illegalCharactersRegex;
    
    public CertainCharactersDocument(String illegalCharactersRegex)
    {
        this.illegalCharactersRegex = illegalCharactersRegex;
    }
    
    @Override
    public void insertString(int offs, String str, AttributeSet a) throws BadLocationException
    {
        if(str.matches(illegalCharactersRegex)) {
            return;
        }
        super.insertString(offs, str, a);
    }
}
Sicherlich keine "Non plus ultra"-Lösung, aber soweit scheint es zu funktionieren und es dient dir vielleicht als Ideenansatz. 🙂
 

Zurück
Oben