Commit cb855cb6 authored by Carsten  Rose's avatar Carsten Rose
Browse files

KeyValueStringParser.php, KeyValueStringParserTest.php: Initial creation: copied from qfq/dhtmlx

parent 0646c749
<?php
/**
* Created by PhpStorm.
* @author: crose
* Date: 7/8/15
* Time: 10:12 AM
*
* $Id$
*/
namespace qfq\helper;
namespace qfq\exceptions;
require_once(__DIR__ . '/../exceptions/UserException.php');
/**
* Class KeyValueStringParser
*
* KeyValueStringParser is a parser for strings of the form
*
* key1<delimiterA>value1<delimiterB>key2<delimiterA>value2<delimiterB>
*
* For instance
*
* id=1,name=doe,firstname=john
*
* - Leading and trailing whitespace will be removed from keys and values.
* - If a value is surrounded by quotes (`'`, * `"`), leading and trailing
* whitespace will be preserved (leading/trailing, quotes will be removed from value).
* - Comments, lines starting with a '#', will be skipped.
*
* @package qfq
*/
class KeyValueStringParser {
/**
* @var string delimiter delimiting key and value
*/
private $keyValueDelimiter;
/**
* @var string delimiter delimiting key/value pairs.
*/
private $listDelimiter;
/**
* Constructor
*
* @param string $keyValueDelimiter delimiter of key/values
* @param string $listDelimiter delimiter of key/value pairs
*/
public function __construct($keyValueDelimiter = ":", $listDelimiter = ",") {
$this->keyValueDelimiter = $keyValueDelimiter;
$this->listDelimiter = $listDelimiter;
}
/**
* Get key/value delimiter
*
* @return string key/value delimiter
*/
public function getKeyValueDelimiter() {
return $this->keyValueDelimiter;
}
/**
* Set key/value delimiter
*
* @param string $keyValueDelimiter key/value delimiter
*/
public function setKeyValueDelimiter($keyValueDelimiter) {
$this->keyValueDelimiter = $keyValueDelimiter;
}
/**
* Get key/value pairs delimiter
*
* @return string key/value pairs delimiter
*/
public function getListDelimiter() {
return $this->listDelimiter;
}
/**
* Set key/value pairs delimiter
*
* @param string $listDelimiter key/value pairs delimiter
*/
public function setListDelimiter($listDelimiter) {
$this->listDelimiter = $listDelimiter;
}
public function unparse(array $keyValueArray) {
array_walk($keyValueArray, function (&$value) {
if (!is_string($value) || $value === "" || strlen($value) === 1) {
return;
}
if ($value[0] === " " && $this->isFirstAndLastCharacterIdentical($value[0])) {
$value = '"' . $value . '"';
}
});
$newKeyValuePairImploded = array();
foreach ($keyValueArray as $key => $value) {
$newKeyValuePairImploded[] = trim($key) . $this->keyValueDelimiter . $value;
}
return implode($this->listDelimiter, $newKeyValuePairImploded);
}
private function isFirstAndLastCharacterIdentical($string) {
if ($string === "") {
return false;
}
return $string[0] === $string[strlen($string) - 1];
}
/**
* Parses key/value pairs string.
*
* Valid: "a:1,b:2,c:,d", "," (empty key AND empty value)
* Invalid: ":" ((empty key forbidden)
*
* @param string $keyValueString string of key/value pairs
*
* @return array associative array indexed by keys
* @throws \qfq\exceptions\UserException
*/
public function parse($keyValueString) {
if ($keyValueString === "") {
return array();
}
$keyValuePairs = explode($this->listDelimiter, $keyValueString);
$returnValue = array();
foreach ($keyValuePairs as $keyValuePairString) {
if ($keyValuePairString === "") {
continue;
}
$keyValueArray = explode($this->keyValueDelimiter, $keyValuePairString, 2);
$key = trim($keyValueArray[0]);
// skip comments
if (substr($key, 0, 1) == '#') {
continue;
}
if ($key === '') {
// ":", ":1"
throw new UserException("Value has no key: '$keyValuePairString'");
}
if (count($keyValueArray) === 2) {
// "a:1", "a:"
$returnValue[$key] = $this->removeSourroundingQuotes(
trim($keyValueArray[1])
);
} else {
// no Value given: "a"
$returnValue[$key] = "";
}
}
return $returnValue;
}
/**
* @param $string
* @return string
*/
private function removeSourroundingQuotes($string) {
$quotes = ['\'', '"'];
if ($string === "" || strlen($string) === 1) {
return $string;
}
if (in_array($string[0], $quotes) === true && $this->isFirstAndLastCharacterIdentical($string)) {
return substr($string, 1, strlen($string) - 2);
}
return $string;
}
}
<?php
/**
* @author Rafael Ostertag <rafael.ostertag@math.uzh.ch>
*/
use qfq\helper\KeyValueStringParser;
require_once(__DIR__ . '/../../qfq/helper/KeyValueStringParser.php');
class KeyValueStringParserTest extends \PHPUnit_Framework_TestCase {
/**
* @var KeyValueStringParser
*/
private $keyValueStringParser;
public function setUp() {
$this->keyValueStringParser = new KeyValueStringParser();
}
public function testSingleKeyValuePair() {
$actual = $this->keyValueStringParser->parse("key:value");
$this->assertCount(1, $actual);
$this->assertArrayHasKey('key', $actual);
$this->assertEquals('value', $actual['key']);
}
public function testKeyWithoutValue() {
$actual = $this->keyValueStringParser->parse("keywithoutvalue");
$this->assertCount(1, $actual);
$this->assertArrayHasKey('keywithoutvalue', $actual);
$this->assertSame("", $actual['keywithoutvalue']);
}
public function testGOODNAMEHERE() {
$actual = $this->keyValueStringParser->parse(",,");
$this->assertCount(0, $actual);
}
/**
* @expectedException \qfq\exceptions\UserException
*/
public function testNoKey() {
$this->keyValueStringParser->parse(":value,key:value");
}
public function testNoValue() {
$actual = $this->keyValueStringParser->parse("key1:,key2:value2");
$this->assertCount(2, $actual);
$this->assertArrayHasKey('key1', $actual);
$this->assertArrayHasKey('key2', $actual);
$this->assertEquals('', $actual['key1']);
$this->assertEquals('value2', $actual['key2']);
}
public function testEmptyKeyValuePairString() {
$actual = $this->keyValueStringParser->parse("");
$this->assertCount(0, $actual);
}
public function testMultipleKeyValuePairs() {
$actual = $this->keyValueStringParser->parse("key1:value1,key2:value2");
$this->assertCount(2, $actual);
$this->assertArrayHasKey('key1', $actual);
$this->assertArrayHasKey('key2', $actual);
$this->assertEquals('value1', $actual['key1']);
$this->assertEquals('value2', $actual['key2']);
}
public function testKeyValueSeparatorInValue() {
$actual = $this->keyValueStringParser->parse("key1:val:ue1,key2:value2");
$this->assertCount(2, $actual);
$this->assertArrayHasKey('key1', $actual);
$this->assertArrayHasKey('key2', $actual);
$this->assertEquals('val:ue1', $actual['key1']);
$this->assertEquals('value2', $actual['key2']);
}
public function testWhiteSpaceHandling() {
$actual = $this->keyValueStringParser->parse(" key1 : val:ue1 , key2 : value2 ");
$this->assertCount(2, $actual);
$this->assertArrayHasKey('key1', $actual);
$this->assertArrayHasKey('key2', $actual);
$this->assertEquals('val:ue1', $actual['key1']);
$this->assertEquals('value2', $actual['key2']);
}
public function testSourroundingQuotes() {
$actual = $this->keyValueStringParser->parse("key1:\" val:ue1 \", key2:' value2 ', key3:\"value3', key4:''");
$expected = [
'key1' => ' val:ue1 ',
'key2' => ' value2 ',
'key3' => "\"value3'",
'key4' => ''
];
$this->assertEquals($expected, $actual);
}
public function testComments() {
$actual = $this->keyValueStringParser->parse(" key1 : val:ue1 , # key2 : value2 , # : broken key value in comment, key3 : valid ");
$expected = [
'key1' => 'val:ue1',
'key3' => "valid",
];
$this->assertEquals($expected, $actual);
}
public function testUnparse() {
$array = $this->keyValueStringParser->parse("key1:\" val:ue1 \", key2:' value2 ', key3:\"value3'");
$actual = $this->keyValueStringParser->unparse($array);
$expected = "key1:\" val:ue1 \",key2:\" value2 \",key3:\"value3'";
$this->assertSame($expected, $actual);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment