JS: Array mittels split erzeugen - Bug??

nietaL

NGBler
Registriert
8 Sep. 2013
Beiträge
231
Ort
Exilgullianer
Hey Leute,

ich habe folgende Funktion in JS geschrieben.

[src=javascript]
function los()
{
// var fruits_liste = 'Banana;Orange;Apple;Mango;'; // A --> 5
// var fruits_liste = ';'; // B --> 2
var fruits_liste = ''; // C --> 1 ???


var fruits_array = fruits_liste.split(";");

alert (fruits_array.length);
}
[/src]

Aus einer Liste, die ihre Elemente durch ein Semikolon trennt, soll ein Array gezaubert werden. Draufhin interessiert mich die Anzahl der Elemente im Array. Dass bei Variante A und B jeweils eins zu viel angezeigt wird, kann ich aufgrund des letztlichen Semikolons noch nachvollziehen und lässt sich allgemein durch alert (fruits_array.length-1); lösen. Wenn aber nun die Liste leer ist, also weder Elemente noch Trennzeichen vorhanden sind, geht mein Menschenverstand davon aus, dass leer=0 sein sollte. Er zeigt mir aber bei alert (fruits_array.length); eine 1 an.

Warum? :confused:
 
Gib dir doch mal das nicht leere Array aus. Vermutlich mit einem leeren Eintrag "".

Wenn du "a".split(";") machen würdest, hättest du am Ende ein Array mit einem Eintrag: ["a"].
Wenn du "".split(";") machst, genau dieselbe Arraylänge, nur eben [""].

Klar?
 
  • Thread Starter Thread Starter
  • #3
Sonderlich logisch finde ich das nicht. Ein Array mit keinem Element ist für mich dasselbe wie eine Array mit einem Element ohne Zeichen. 1x0 und 0x1 ist schließlich in der Mathematik auch dasselbe. Ist das in allen Programmiersprachen so?

if (fruits_array[0] == '') {fruits_array = [];}

Wäre das dann legitim?
 
Das ist völlig logisch :) In der Informatik gibt es als Datentyp-Unterart das sog. "leere Wort", also eine als String deklarierte Variable ohne Inhalt. Obwohl leer, stellt dieser leere Wert eine Information dar - ähnlich einer 0 als Zahl.

Split hat eine Eigenart: bei nicht erfolgtem Teilen wird der Ausgangsstring zurückgegeben. Wenn Du also '' anhand von ";" splittest, kann nicht gesplittet werden und '' wird zurückgegeben.

In Deinem Fall macht eine Bereiningung Sinn - hier ein schnell zusamengeschustertes Beispiel:

[src=javascript]function los(){
// var fruits_liste = 'Banana;Orange;Apple;Mango;'; // A --> 5
// var fruits_liste = ';'; // B --> 2
var fruits_liste = ''; // C --> 1 ???


if(fruits_liste != ''){
if(fruits_liste.substr(-1,1) == ';'){
fruits_liste = fruits_liste.substr(0,fruits_liste.length -1)
}

var fruits_array = fruits_liste.split(';');

if(typeof fruits_array === 'object'){
alert (fruits_array.length);
}
}
else{
alert ('Keine Werte in CSV, kein Array');
}
}[/src]

Übrigens wäre es besser, anstatt den Ausgangsstring zu bereinigen, das Schreiben entsprechend anzupassen, also nach dem letzten Wert kein Semikolon zu schreiben.

Gruß, J.
 
Zuletzt bearbeitet:
Ich schätze, .split() generiert immer ein Array und überprüft vorher nicht, ob der Eintrag leer ist. Wenn man nämlich auf das gesplittete Array an Position [0] zugreifen möchte, ist es nie undefined, egal ob leerer String oder nicht.

Deine if-Abfrage sollte so funktionieren. Allerdings würde ich schon vorher prüfen, ob der Inputstring leer ist, und dann erst gar nicht splitten.
 
  • Thread Starter Thread Starter
  • #6
vielen Dank. Ich bin überzeugt. Habe es jetzt so hinbekommen.

Aber hier habe ich noch so ein Phänomen. Diesmal habe ich bestimmt einen BUG in JS entdeckt :D
Warum ergibt dieses Skript die Antwort 'Ananas'? Hat es auch etwas mit leeren Arrays zu tun?

[src=javascript]
function los(BS)
{
obst = new Array('Apfel', 'Ananas', 'Avocado');

for(var i=0; i < obst.length; i++)
{
if(obst.substr(0,1).match(BS))
{
obst.splice(i,1);
}
}
alert (obst.join(', '));
}
[/src]
[src=html4strict]
<input type="button" onClick="los('A');" value="looooos">

[/src]

Wenn ich Birne zum Array hinzufüge, kommt 'Birne, Ananas'... Als begänne Ananas nicht mit A.
 
Über eine Datenstruktur zu iterieren, und dann in der Schleife die Anzahl der Elemente zu ändern o.ä. ist in der Regel böse, du bist jetzt auch darüber gestolpert.
Überleg dir einfach mal, wie das Array nach dem ersten Durchlauf in der for-Schleife aussieht und was dann genau im zweiten Durchlauf gemacht wird.
 
  • Thread Starter Thread Starter
  • #8
ach verdammt. klar! Das Array verändert sich ja mit jedem Durchlauf. :m

Gibt es eine eine elegante und einfache Möglichkeit, mehrere Elemente zu löschen?
 
Du wirst vermutlich eine Kopie des Arrays erzeugen wollen und über dieses dann iterieren.
 
Speicher doch die Werte, die NICHT gelöscht werden, in einem neuen Array und gibst das zurück?
 
Ja, so herum ist es vermutlich netter. Jedenfalls musst du mit zwei Arrays arbeiten.
 
  • Thread Starter Thread Starter
  • #12
sehr gute Idee. habe so ein temporäres array angelegt und das ursprüngliche dann durch jenes ersetzen lassen. wieder etwas gelernt. vielen dank. :coffee:
 
Hey Leute,

ich habe folgende Funktion in JS geschrieben.

[src=javascript]
function los()
{
// var fruits_liste = 'Banana;Orange;Apple;Mango;'; // A --> 5
// var fruits_liste = ';'; // B --> 2
var fruits_liste = ''; // C --> 1 ???


var fruits_array = fruits_liste.split(";");

alert (fruits_array.length);
}
[/src]

Aus einer Liste, die ihre Elemente durch ein Semikolon trennt, soll ein Array gezaubert werden. Draufhin interessiert mich die Anzahl der Elemente im Array. Dass bei Variante A und B jeweils eins zu viel angezeigt wird, kann ich aufgrund des letztlichen Semikolons noch nachvollziehen und lässt sich allgemein durch alert (fruits_array.length-1); lösen. Wenn aber nun die Liste leer ist, also weder Elemente noch Trennzeichen vorhanden sind, geht mein Menschenverstand davon aus, dass leer=0 sein sollte. Er zeigt mir aber bei alert (fruits_array.length); eine 1 an.

Warum? :confused:

Nein, dass ist alles vollkommen richtig, so wie es passiert.
Die Zerlegung (split) findet um das Trennzeichen herum statt.
In der Informatik verwendet man meist das sog. leere Wort, um zum verdeutlichen, was passiert.
'' entspricht dem leeren Wort, also einem Wort der Länge 0.

[src=javascript]var fruits_liste = 'Banana;Orange;Apple;Mango;';
var fruits_array = fruits_liste.split(';'); // ist array('Banana', 'Orange', 'Apple', 'Mango', '');

var fruits_liste = ';';
var fruits_array = fruits_liste.split(';'); // ist array('', '');

var fruits_liste = '';
var fruits_array = fruits_liste.split(';'); // ist array('');[/src]

Im Fall 1 besteht der String aus: Banana;Orange;Apple;Mango;<LeeresWort>
Im Fall 2 besteht der String aus: <LeeresWort>;<LeeresWort>
Im Fall 3 besteht der String aus: <LeeresWort>
Fall 1 kann also in Banana, Orange, Apple, Mango und <LeeresWort> aufgesplittet werden.
Fall 2 kann also in <LeeresWort> und <LeeresWort> aufgesplittet werden.
Fall 3 kann nicht aufgetrennt werden, das einzige Element ist also <Leeres Wort>.

--- [2016-06-06 14:46 CEST] Automatisch zusammengeführter Beitrag ---

Sonderlich logisch finde ich das nicht. Ein Array mit keinem Element ist für mich dasselbe wie eine Array mit einem Element ohne Zeichen.
Nein, ein Array ohne Elemente ist
var emptyArray = []; bzw. var emptyArray = new Array();
Ein Array mit einem Element mit 0 Zeichen ist var emptyArray = ['']; bzw. var emptyArray = new Array('');
Und nein, das ist nicht gleich. Ein Array ist eine Sammlung von Zeigern. Wobei jeder Zeiger auf einen Wert zeigen kann.
Ein leeres Array enthält 0 Zeiger. Ein Array mit einem Element enthält zwangsweise einen Zeiger. Dieser kann, muss jedoch nicht, auf ein leeres Wort zeigen.

Natürlich ist für dich ein leeres Stück Papier im Ergebnis gleich einem Stück Papier auf dem kein Zeichen drauf geschrieben ist, aber in der Informatik gibt es da eben doch Unterschiede. Bei einem Array kannst du an einen Setzkasten denken, in den du kleine Zettel mit Verweisen legst, auf denen steht, wo sich der Gegenstand befindet.
Ein leeres Array ist ein Setzkasten, in dem sich kein Zettel befindet. Ein Array mit einem Element, welches auf das leere Wort verweist, ist wie ein Setzkasten mit einem Zettel auf dem nichts drauf steht.

Ist das in allen Programmiersprachen so?
Ja. Wie gesagt handelt es sich dabei um das leere Wort. Das leere Wort musst du unbedingt von "nichts" unterscheiden.
'' ist ein leerer String, was du willst ist null.

[src=javascript]if (fruits_array[0] == '') {fruits_array = [];}[/src]
Nein, pauschal kannst du das nicht machen:
var fruits_string = ";Affe;Bär"; // ['', 'Affe', 'Bär']
 
Ein weiterer Vorschlag wäre z.B. zu gucken
1. ob ein Semikolon schon am Anfang steht
2. ob 2 Semikolons hintereinander vorkommen
3. ob ein Semikolon am Ende des Strings steht
4. ob ein "&" im String vorkommt, was darauf hinweisen kann, dass es codierte Sonderzeichen im String gibt wie z.B. " " oder "ü", "ä" etc. was Probleme beim Splitten verursachen könnte.
[src=javascript]
if ((fruits_list.indexOf(";") == 0) || (fruits_list.indexOf(";;") > -1) || (fruits_list.lastIndexOf(";") == fruits_list.length-1) || (fruits_list.indexOf("&") > -1)){
alert("fruits_list enthält leere/Fehlerhafte Einträge");

fruits_list = fruits_list.replace(";;",";");
fruits_list = fruits_list.replace("/;$/g","");
fruits_list = fruits_list.replace("/^;/g","");

// hier werden 2 durchläufe an bereinigungen durchgeführt, damit auch strings wie "&nbsp;" aus der fruits_list gefiltert werden.

var ta = document.createElement("textarea");
ta.innerHTML = fruits_list ;

var ta2 = document.createElement("textarea");
ta2.innerHTML = ta.value;

fruits_list = ta2.value;
fruits_list = fruits_list .replace(";;",";");
fruits_list = fruits_list .replace(/;$/,"");
fruits_list = fruits_list .replace(/^;/,"");

} else {
var fruits_array = fruits_liste.split(";");
}
[/src]
;)
 
Zuletzt bearbeitet:
  • Thread Starter Thread Starter
  • #15
Oh, vielen dank noch einmal für die weiteren ausführlichen Kommentare. Ich habe ein Einsehen, dass ein leeres Papier nicht dasselbe ist wie kein Papier :T
 
Zurück
Oben