Ich habe, aufgrund von anderem Verwendungszweck, einen relativ simplen Parser für INI-Dateien geschrieben. Der Syntax ist nicht ganz der, den man vielleicht kennt, aber ähnlich und beitet etwas mehr freiheiten.
Key-Value paare werden mithilfe des = deklariert, jede anweisung trennt eine Zeile.
Wird ein key doppelt definiert, wird der alte überschrieben.
Zeieln können belibig eingerückt werden, leere Zeilen und die, die mit einem # beginnen, werden ignoriert. Ein # würde hier also ein KOmmentar bezeichnen.
Bei den Sections liegt der größte unterschied. Denn, auch aus gründen des Codeverständinnes und der Vermeidung unnötiger kompliziertheit, muss deren Ende gekennzeichnet werden.
Eine Section nicht zu beenden, endet in einer Exception.
Sections können beliebig oft in einander verschalchtelt werden, es macht hier auch keinen unterschied, ob vor oder nach einer inneren section Key-Value paare stehen.
key=value
[section1]
key=value
[section1.1]
key=value
[END]
key2=value
[section1.2]
key=value
[END]
[END]
Alles anzeigen
Achtung: Die vielen key=value im oberen Beispiel überschreiben sich nicht.
EDIT: Sorry, das hab ich vergessen:
Achtung: Sections die doppelt definiert sind, werden ebenfalls überschrieben.
Nun zu den freiheiten, von denen ich gesprochen habe: Ein = in einer anweisung ist nicht zwingen nötig. Somit kann man quasi listen definieren:
Soviel zum Syntax.
Die Verwendung in PHP:
Vom perser kommt ein Array zurück, das die Key-Value paare enthält. Sections sind ein Array mit gleichen beedingungen, wie das ausgangs-Array.
// je nachdem, wie man die Klasse an/ablegt
include("INIParser.class.php");
$file="userdata.ini";
$user=INIParser::parseFile($file);
echo "Benutzername: ".$user['name'];
echo "Spricht folgende Sprachen: ".implode(",", $user['sprachen']);
um als Beispiel hier noch das Array, dass INI::parseFile zurück gibt aufzuzeigen:
Zusätzlich zu INIParser::parseFile gibt es ncoh INIParser::parse. Diese Methode nimmt ein Array (oder einen String, den sie mithilfe von explode bei \n´s nach zeilen zeilt).
Achtung: INIParser::parse und INIParser::parseFile sind statisch und INIParser abstrakt.
Hier der Quellcode:
abstract class INIParser {
public static function parse($c) {
if (gettype($c)!="array") {
if (gettype($c)=="string") {
$c=explode("\n", $c);
} else return false;
}
$ar=array();
$j=count($c);
$line_nr=0;
while ($line_nr<$j) {
$line=trim($c[$line_nr]);
if (substr($line, 0, 1)=="#") {
$line_nr++;
continue;
}
if (empty($line)) {
$line_nr++;
continue;
}
if (substr($line, 0, 1)=="[' && substr($line, strlen($line)-1)==']") {
$name=substr($line, 1, strlen($line)-2);
$dept=0;
$end=false;
$n=$line_nr;
while ($n<$j) {
$line2=trim($c[$n]);
if ($line2=="[END]") {
$dept--;
if ($dept==0) {
$end=true;
break;
}
} else if (substr($line2, 0, 1)=="[' && substr($line2, strlen($line2)-1)==']") {
$dept++;
}
$n++;
}
if ($end===false) {
throw new Exception("Unexpected end of section ['.$name.'] on line ".$j." in [parent]");
}
$sec=array_slice($c, $line_nr+1, $n-$line_nr-1);
$ar[$name]=INIParser::parse($sec);
$line_nr=$n;
} else {
$pos=strpos($line, "=");
if ($pos==false) {
$ar[]=trim($line);
} else {
@$ar[trim(substr($line, 0, $pos))]=trim(substr($line, $pos+1));
}
}
$line_nr++;
}
return $ar;
}
public static function parseFile($file) {
return self::parse(file($file));
}
}
Alles anzeigen
Feedback herzlich willkommen, aber bitte Konstruktives.