# Plausibilitätskontrolle - Doppelte Werte entfernen



## Maddili (19. Mai 2010)

Hi, ich hab wiedereinmal ein Problem:

Meine Textdatei wird zeilenweise durchsucht.
Alle Zeilen, die nicht mit einem Semikolon (' ; ') beginnen, werden per Substring zerlegt und die eigentlich wichtige Information herausgefiltert.

Die Textdatei ist ~so aufgebaut:


Network1Flag26_O		= Befehl Sonstwas

;Network1Flag27_O		= Befehl Sonstwas
Network1Flag26_O		= Befehl Sonstwas

;Network1Flag27_O		= Befehl Sonstwas;
;Network1Flag28_O 		= Befehl Sonstwas;
;Network1Flag29_O 		= Befehl Sonstwas;

Network1Flag30_O 		= Befehl Sonstwas;
Network1Flag31_O 		= Befehl Sonstwas;

TempFlag02_O		= Befehl Sonstwas
TempFlag03_O		= Befehl Sonstwas
TempFlag04_O			= Befehl Sonstwas
TempFlag05_O		= Befehl Sonstwas

Hier mal mein Quelltext:


```
public static void Plausibilitaet(){

		if(DateiChooser.uebergabe==null){
		System.out.println("..." + DateiChooser.uebergabe);
		DateiChooser.auswahlDatei();
		}

		ergebnis="";
		try {


			FileInputStream inputstream=new FileInputStream(DateiChooser.uebergabe);
			InputStreamReader reader=new InputStreamReader(inputstream);
			BufferedReader bff=new BufferedReader(reader);


			String zeile=null;
			String[] array = new String[800];
			String[] array2 = new String[800];
			
			int i=0;


			while ((zeile = bff.readLine()) != null ) {

				if(zeile.lastIndexOf("=") > 0 && !zeile.startsWith(";")){

					String sub = zeile.substring(0, zeile.lastIndexOf("="));
					sub.replaceAll(" ", "");
					sub.trim();
					System.out.println("SUB: " + sub + "#");

					array[i] = sub;
					array2[i] = sub;
					i++;



				}
					befehlanzahl++;
			}



			// Hier meine Überprüfung, welche Einträge doppelt vorhanden sind
			int a=0;

			for(int x=0; x<array.length; x++){

				for(int y=0; y<array2.length; y++){
					if(array[x].equals(array2[y]) && x!=y){
						System.out.println("X: " + x + ";  Y: " + y + "   " + array[x]);
						ergebnis=ergebnis+array[x]+"\n";
						a++;
					}else{
					}
				}


			}


			} catch (Exception e) {
				System.out.println("GEHT NICHT!");
				System.out.println("exception: " +e);
				}


			Object[] options = {"Weiter..",
	            	            	                "Datei öffnen",
					};

			int n = JOptionPane.showOptionDialog(new JFrame(),
			"Folgende Parameter kommen mindestens doppelt vor: \n\n"
			+ ergebnis,
			"Warnung!",
			JOptionPane.YES_NO_OPTION,
			JOptionPane.WARNING_MESSAGE,
			null,
			options,
			options[1]);


			switch (n){
			case 0: System.out.println("Case 0 ");
					break;
			case 1: System.out.println("Case 1 ");
					try {
		            	Runtime.getRuntime().exec( "rundll32 url.dll,FileProtocolHandler " + DateiChooser.uebergabe );
		            }
		            catch ( Exception  e ) {

		              e.printStackTrace();
		            }


			}
	}
```


Die rot markierten Passagen gefallen mir überhaupt nicht.
Das mit dem .trim() bzw. replace funktioniert überhaupt nicht. (siehe Anhang)
Es muss doch eine bessere Lösung geben, wie diese beiden Arrays zu vergleichen. 
Hab mich jetzt schon stundenlang mit Arraylists, Hashmaps, zweidimensionalen Arrays usw herumgeschlagen. Ich checks einfach nicht. 
Kann mir jemand evtl sagen, wie die Methode besser zu strukturieren ist?

Im Anhang mal die Ausgabe der Konsole mit dem Popup der doppelten Einträge.

mfg
Maddin


----------



## Matt297 (19. Mai 2010)

Hi, wie ich vermute willst du die Namen der ganzen (nicht kommentierten) Flags in ein Feld stecken und es dürfen auch keine Duplikate vorkommen.

Meine persönliche Meinung ist, dass so ziemlich alle Subinterfaces von Collection(List,Vector,Set,etc) besser sind als Arrays

In deinem Fall würde ich dir empfehlen eine Menge(Set) zu benutzen, z.B. eine HashSet die eignet sich gut für solche Zwecke. Eine Set zeichnet sich dadurch aus, das jedes Element nur einmal vorkommen darf, wenn ein Objekt in eine Set eingefügt werden soll, dass schon vorhanden ist, dann wird es einfach verworfen und die add()-methode liefert ein false zurück. Das ist schonmal eine gute Methode um Duplikate von vornherein zu vermeiden.
Außerdem liefern Sets einen Iterator, so dass man ohne großen Aufwand durch die Daten iterieren kann.

Ich kann dir mal ein Beispiel zeigen wie man eine Set verwendet:


```
...
Set<String> foo = new HashSet<String>(); //Eine HashSet, die nur String-Objekte aufnimmt erzeugen
for(int i = 0; i < 10; i++) 
{
  if (!foo.add(new Integer(i).toString())) //Set mit 10 Strings füllen
    System.out.println("Element " + new Integer(i).toString() + " bereits vorhanden"); //würde in diesem Fall nicht vorkommen 
}

for (String bar : foo) //vereinfachter Schleifenkopf, möglich durch den Iterator
{
  System.out.println(bar);
}
```

Das ist jetzt nur ein rudimentäres Beispiel, wie man mit einer Set(oder auch anderen Collections) umgehen kann, genauer nachlesen kannst du das in derJava-insel. Da stehen auch mehr Informationen zu anderen Methoden, die die Set bietet(contains, toArray, ...).

Zu deiner anderen rot markierten Stelle. Das replaceAll ist in dieser Stelle falsch. Wenn du in der JavaDoc nachschaust, siehst du dass die Methode als ersten Parameter einen regex erwartet. 
In deinem Fall müsstest du die Methode replace nehmen:

```
public String replace(CharSequence target, CharSequence replacement)
```
Und das trim() entfernt nur alle whitespaces am Anfang und am Ende des Strings, sprich eine Kombination aus replace(" ","") - oder auch replace(' ', ''), weil es die replace-Methode auch mit (char,char) gibt - und trim() würde alle Leerzeichen entfernen, so wie du es glaub ich gerne hättest.

Ich hoffe ich konnte dir helfen, was genau verstehst du den an Lists und Maps nicht? Ich werde sie dir gerne erklären, weil die das Programmieren im Vergleich zu Arrays echt erleichtern.


----------



## hansmueller (19. Mai 2010)

Hallo,

daß das trim() nicht funktioniert könnte vielleicht auch an der Zeichencodierung der Textdatei liegen, die du einliest.

Probier es mal so:

```
new InputStreamReader(inputstream, Charset.forName("UTF-16"))
```

Natürlich must du statt "UTF-16" die Codierung nehmen, in welcher die Textdatei vorliegt.

MfG
hansmueller


----------



## Maddili (19. Mai 2010)

Hi, vielen Dank für die Antwort.



> und trim() würde alle Leerzeichen entfernen, so wie du es glaub ich gerne hättest.



Ja, das hätte ich gerne   Macht es aber nicht. (außer ich mache es falsch - siehe den Test mit den ' # ' in meinem Screenshot.)

Der Text (aus meiner Datei), den ich zu Anfangs geschrieben habe, beinhaltet auch etliche Leerzeichen, die hier leider nicht angezeigt werden.
Hier mit  ' _ ' statt ' space ' (es ist auch unregelmäßig, wieviele Leerzeichen pro Zeile - deshalb würde ich sie gerne trimmen)


> [...]
> Network1Flag26_O____________= Befehl Sonstwas
> 
> ;Network1Flag27_O__________= Befehl Sonstwas
> ...






> was genau verstehst du den an Lists und Maps nicht?


Gute Frage... ..ich teste und probiere seit heute Vormittag mit dem Mist herum, hat kein einziges mal funktioniert.

mfg Maddin


----------



## Maddili (19. Mai 2010)

HA!!
Habs geschafft - Vielen Dank. War eigentlich gar nicht sooo schwierig... ...eigentlich viel einfacher, wie mit den beiden Arrays 

Wen´s interessiert:


```
while ((zeile = bff.readLine()) != null ) {

				if(zeile.lastIndexOf("=") > 0 && !zeile.startsWith(";")){

					String sub = zeile.substring(0, zeile.lastIndexOf("="));

					hs.add(sub.trim());
					if(hs.add(sub)==false){
						falsevalues = falsevalues+sub.trim() + "\n";
					}

				}
					befehlanzahl++;
			}

			System.out.println("falsevalues: " + falsevalues);




//.....
```

Sogar das trim() funktioniert! 

Danke und schönen Abend noch - ich melde mich nächste Woche wieder 

Maddin


----------



## Matt297 (19. Mai 2010)

Das ist ja schön, das es funktioniert 

Ich seh auch schon warum es nicht funktioniert hat und könnte mich hauen, weil ich es nicht früher rausbekommen habe 

So wie du es hattest,

```
sub.trim();
```
hatte zur Folge dass der String aus "sub" getrimmt wird und zurückgegeben wird, aber da keine Zuweisung erfolgt, verfällt der Rückgabe-wert.
Richtig wäre also

```
sub = sub.trim();
```

Das ist vergleichbar mit folgendem Beispiel:


```
String foo = new String("abc");
foo + "def"; //Diese zeile würde - semantisch gesehen - nichts bringen
foo = foo + "def"; //das würde erst bewirken dass in foo "abcdef" steht
foo += "def"; //ist so ziemlich dasselbe
```

Eine kleine Anmerkung noch, da die add-Methode einen boolean Wert zurückgibt kannst du folgende Zeile:

```
if(hs.add(sub)==false){
```
auch durch folgende Zeile ersetzen:

```
if(!hs.add(sub)){
```
Ich finde, dass hat ein bisschen was von besserem Programmierstil. Da die Methode sowieso ein boolean zurückgibt, ist es überflüssig den Wert nochmal mit einem boolean zu vergleichen. Da ist es einfacher die Bedingung zu invertieren(mit dem "!").

Ich kann dir zum lernen die Java Insel(einfach mal danach googlen) empfehlen, es ist ein freies deutschsprachiges Buch, das wirklich sehr ausführlich erklärt und oft auch sehr in die Tiefe geht.

Gruß

Matt


----------



## Maddili (28. Juli 2010)

Hi, ich muss diesen Thread nochmals hoch holen.

Habe meine Plausibilitätskontrolle folgendermaßen gelöst:


```
FileInputStream inputstream=new FileInputStream(DateiChooser.uebergabe);
InputStreamReader reader=new InputStreamReader(inputstream);
BufferedReader bff=new BufferedReader(reader);
String zeile=null;

while ((zeile = bff.readLine()) != null ) {
	if(zeile.lastIndexOf("=") > 0 && !zeile.startsWith(";")){
		String sub = zeile.substring(0, zeile.lastIndexOf("="));
		hs.add(sub.trim());
		if(hs.add(sub)==false){
			falsevalues = falsevalues+sub.trim() + "\n";
					}
				}
			befehlanzahl++;
			}
```



Jetzt ist mir aufgefallen, dass in meiner Konfigurationsdatei auch folgende Werte vorkommen:

Timer02(2) = Voltagefault_I;

Der Wert in der Klammer ist die Zeit (2 Sekunden), mit der der Timer belegt wird.
Da mein Substring nur den ersten "Block" bis zum "=" trimmt und vergleicht, kann es aber sein, dass ich mein Timer02 nochmals belegt wird. Also:

Timer02(2) != Timer02(4) => folglich erkennt er die "Doppelbelegung" nicht.

Ich wollte es SO lösen, klappt aber nicht.


```
while ((zeile = bff.readLine()) != null ) {
	if(zeile.lastIndexOf("=") > 0 && !zeile.startsWith(";")){
		String sub = zeile.substring(0, zeile.lastIndexOf("="));
		if(!sub.contains("(")){
			hs.add(sub.trim());
			if(hs.add(sub)==false){
				falsevalues = falsevalues+sub.trim() + "\n";
			}
		}else{
			String sub2 = sub.substring(0, sub.lastIndexOf("("));
			hs.add(sub2.trim());
			if(hs.add(sub2)==false){
				falsevalues = falsevalues+sub.trim() + "\n";
			}
		}
	}
		befehlanzahl++;
}
```

Was habe ich falsch gemacht? Mein Sub2 wird generell NICHT geaddet.

mfg
Maddin


----------



## Franz Degenhardt (28. Juli 2010)

Maddili hat gesagt.:


> ```
> hs.add(sub.trim());
> if(hs.add(sub)==false){
> falsevalues = falsevalues+sub.trim() + "\n";
> ...


 
Der erste Aufruf von add() fügt das Element hinzu. Bei einem Set wird dann der Aufruf des zweiten add() mit dem selben Objekt fehlschlagen. An dieser Stelle fügst du einmal eine getrimmte Version des Strings ein und in der Zeile danach nochmal die ungetrimmte Version.

Die Prüfung auf if (hs.add(sub)) führt impliziet die Methode aus und führt den Rückgabewert der Prüfung von if zu. 
Passend wäre vermutlich

```
if(hs.add(sub.trim())) {
// ist geadded worden
} else {
 // ist nicht geadded worden
  falsevalues = falsevalues+sub.trim() + "\n";
}					}
```


----------



## Maddili (28. Juli 2010)

```
String sub = zeile.substring(0, zeile.lastIndexOf("="));
		hs.add(sub.trim());
		if(hs.add(sub)==false){
			falsevalues = falsevalues+sub.trim() + "\n";
					}
```

So wie ichs bisher hatte, funktioniert es ja wunderbar.
ABER: 
Ich bräuchte eine Differenzierung des Strings:
1. Enthält der String KEIN '(' bzw. '()', mache nen Substring(sub) und schreibe ihn ins HashSet(hs) 
Oder
2. String enthält ein '(' bzw. '()' => mache einen Substring(sub2) vom Substring(sub) und schreibe ihn ins Hashset.

=> Bei den Werten, welche bereits im hs vorhanden sind, wird false zurück gegeben und in falsevalues hinzugefügt.

Werd nicht wirklich schlau aus dem Beitrag.

mfg
Maddin


----------



## Franz Degenhardt (29. Juli 2010)

Deinen Metacode kann man 1:1 in Java umsetzten, viel fehlt nicht. Die Prüfung auf die Klammer scheint ja schon in Ordnung zu sein.
Ich wollte aufzeigen, dass in den zwei zitierten Zeilen mehr als geplant und wahrscheinlich was anderes als das geplante stattfindet.

- die Methode add() innerhalb einer if-Bedingung aufzurufen ändert nichts an deren Arbeitsweise. Die Methode wird ausgeführt - einmal zuviel vermutlich, da in der Zeile darüber schon ein Aufruf ist.
- beim zweiten Aufruf von add() in der if-Bedingung gibst du als Parameter sub diesmal ungetrimmt mit. 

> Bei den Werten, welche bereits im hs vorhanden sind, wird false zurück gegeben und in falsevalues hinzugefügt.

Genau dies passiert nicht. Stattdessen wird das getrimmte sub geadded und danach nochmal das ungetrimmte sub. Für das adden des ungetrimmte sub gibt es dann eine Prüfung.


----------

