Author Topic: str_to_array - Convert a string to an array  (Read 469 times)

0 Members and 1 Guest are viewing this topic.

Offline jchookTopic starter

  • Irregular
  • Posts: 4
    • View Profile
str_to_array - Convert a string to an array
« on: July 11, 2010, 05:42:50 PM »
str_to_array()

Since I think this is an important feature that can be used in many ways (including WordPress Filters / Plugins), I thought I would come on here and post my str_to_array() function.
[It's my first post. I don't really need help at the moment, but the PHP Snippets forum is READ ONLY, so here I am.]

Using eval() as suggested here is dangerous. If you ran CMS content through eval(), any php-savvy author on the system could effectively gain admin access to the depths of your CMS and beyond. Hence my need for this function.

Features
  • Simplified syntax that is whitespace-insensitive like PHP
  • No regular expressions, so it's lightweight.
  • Eval functionality if you want it. The functionality can be disabled either through an if-statement or by commenting out that portion of the code.
  • Nested arrays for more complex applications
  • Escape character support (\) for putting special characters in your array content


# function str_to_array()
#
# Converts a simple string expression into an array.
# Supports simple syntax, nested arrays and nested PHP.
#
# @version 1.0
# @author  Wesley Roberts
# @date    July 11, 2010
# @link    http://fire.cowfight.com/
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

function str_to_array($str$var_sep=','$val_sep='=') {
	

	
# Defaults
	
if (!
is_string($str)) return null;
	
$r = array();
	

	
# Whitespace
	
$skip = array(" ","\t","\n","\r");
	

	
# Trim whitespace
	
$str trim($strimplode($skip));
	

	
# Remove array notation if necessary
	
# NOTE that trim will not work here
	
# AND they are individual on purpose
	
if (
substr($str,0,1) == '[')
	
	
$str substr($str,1);
	
if (
substr($str,-1,1) == ']')
	
	
$str substr($str,0,-1);
	

	
# Always end the string with $var_sep
	
$str .= $var_sep;
	
$len strlen($str);
	

	
# Defauts
	
$buf ''# buffer
	
$key 0;  # next array key
	
$inc 0;  # next numeric array key
	
$esc false# escaped char?
	

	
# Go through each character
	
for (
$i=0$i<$len$i++) :
	
	

	
	
if (
$esc) :
	
	
	
$buf .= $str[$i];
	
	
	
$esc false;
	
	
	
continue;
	
	
endif;
	
	

	
	
switch(
$str[$i]):
	
	
	

	
	
	
# Association operator
	
	
	
case 
$val_sep:
	
	
	
	
if (!empty(
$buf)) :
	
	
	
	
	
$key $buf;
	
	
	
	
	
$buf '';
	
	
	
	
endif;
	
	
	
break;
	
	
	

	
	
	
# PHP! Note: this clears the buffer!!!
	
	
	
# If you need to prefix your results,
	
	
	
# do it within the braces.
	
	
	
case 
'{' :
	
	
	
	
$end str_delimiter_pos_r($str$len$i'{''}');
	
	
	
	
$buf = eval(substr($str$i+1$end-$i-1)); // excluding braces
	
	
	
	
$i $end;
	
	
	
break;
	
	
	

	
	
	
# Sub-array notation is recursive
	
	
	
case 
'[':
	
	
	
	
$end str_delimiter_pos_r($str$len$i);
	
	
	
	
$buf str_to_array(substr($str$i$end-$i));
	
	
	
	
$i $end# will be incremented
	
	
	
break;
	
	
	

	
	
	
# Quotations to have spaces
	
	
	
case 
"'":
	
	
	
case 
'"':
	
	
	
	
$end str_delimiter_pos_r($str$len$i$str[$i], $str[$i]);
	
	
	
	
$buf substr($str$i+1$end-$i-1); // excluding quotes
	
	
	
	
$i $end;
	
	
	
break;
	
	
	

	
	
	
# Escape character
	
	
	
case 
'\\':
	
	
	
	
if (!
$esc) :
	
	
	
	
	
$esc true;
	
	
	
	
	
$buf .= $str[$i+1];
	
	
	
	
	
$i++;
	
	
	
	
else : 
	
	
	
	
	
$buf .= '\\';
	
	
	
	
endif;
	
	
	
break;
	
	
	

	
	
	
# Variable separator
	
	
	
case 
$var_sep :
	
	
	
	
$r[$key] = $buf;
	
	
	
	
if (
is_numeric($key))
	
	
	
	
	
$inc++;
	
	
	
	
$key $inc;
	
	
	
	
$buf '';
	
	
	
break;
	
	
	

	
	
	
# Default
	
	
	
default:
	
	
	
	
if (! 
in_array($str[$i], $skip))
	
	
	
	
	
$buf .= $str[$i];
	
	
	
break;
	
	

	
	
endswitch;
	

	
endfor;
	

	
# Return the final value
	
return 
$r;
}

# THIS FUNCTION IS REQUIRED BY str_to_array()
# Looks for the closing delimiter ($rchar). 
# Assumes that the first char ($offset=0) is the opening delimiter ($lchar).
#
function str_delimiter_pos_r(&$str, &$len=0$offset=0$lchar='['$rchar=']') {
	
$r $offset+1;
	
for (
$r$r<$len$r++) :
	

	
	
# Escape character
	
	
if (
$str[$r] == '\\')
	
	
	
$r++;
	
	

	
	
# Sub delimiters
	
	
# (this only works when the delimiters are distinct)
	
	
elseif ((
$str[$r] == $lchar) && ($lchar != $rchar))
	
	
	
$r str_delimiter_pos_r($str$len$r$lchar$rchar);
	
	

	
	
# Whew. We made it.
	
	
elseif (
$str[$r] == $rchar)
	
	
	
return 
$r;
	
endfor;
	
return 
$len;
}



It's probably best to learn by example for this one:

# The simplest usages
str_to_array('[]'// Array ()
str_to_array('[something]'// Array ( 'something' )
str_to_array('["something with spaces"]'// Array ( 'something with spaces' )
str_to_array('[ a=1, b=2, c=3]'// Array ( 'a'=>'1', 'b'=>'2', 'c'=>'3' )


For a more comprehensive display of its capabilities

print_r
(str_to_array('
	
[
	
	
first = [assigned, associatively],
	
	
	

	
	
[an,array,all,alone],
	
	

	
	
"something else" = [ array = values ],
	
	

	
	
"just a value",
	
	

	
	
"some php generated text" = {
	
	
	
return "Today\'s Date Is ".date(\'m-d-Y\');
	
	
}
	
]
'
));


The above code will output:
Code: [Select]
/* OUTPUT:
Array
(
    [first] => Array
        (
            [0] => assigned
            [1] => associatively
        )

    [0] => Array
        (
            [0] => an
            [1] => array
            [2] => all
            [3] => alone
        )

    [something else] => Array
        (
            [array] => values
        )

    [1] => just a value
    [some php generated text] => Today's Date Is 07-11-2010
)

See Also

Offline wildteen88

  • Guru
  • 'Insane!'
  • *
  • Posts: 12,021
  • Gender: Male
    • View Profile
Re: str_to_array - Convert a string to an array
« Reply #1 on: July 11, 2010, 06:00:43 PM »
Your function is sort of similar to json_encode() and json_decode().

Cant see the use in your function though. Where would I use this?
« Last Edit: July 11, 2010, 06:02:31 PM by wildteen88 »

Offline jchookTopic starter

  • Irregular
  • Posts: 4
    • View Profile
Re: str_to_array - Convert a string to an array
« Reply #2 on: July 11, 2010, 08:43:25 PM »
You would use this function to accept user input in a CMS context. For example, suppose you have a gallery module that your users would like to include in their page content. You can specify a content filter that accepts input in a fashion that is very easy for a user to write (about as easy as BBCode).

This is a suggested syntax, though the syntax can be customized (the function is rather simple).
Code: [Select]
[my_module_name, 
    title = "My Custom Title", 
    gallery = "My First Gallery",
    height = 300,
    width = 500 ]

Moreover, since it is fairly robust (though certainly could use some improvements), this type of user input can be standardized across many plugins or modules to provide the user with some level of consistency.

Offline jchookTopic starter

  • Irregular
  • Posts: 4
    • View Profile
Re: str_to_array - Convert a string to an array
« Reply #3 on: July 11, 2010, 09:29:33 PM »
Can't figure out how to edit my first post, but I made some improvements just now. I think this thing has many uses if you just think along the lines of accepting user input. Whatever though, it's useful to me! Just sharing.

New in this version:
  • true and false now evaluate as actual boolean values. To use the string versions, just put quotes around them.
  • Fixed the empty array problem (returned an array with one element)
  • Fixed the weird escape character business
  • Fixed the argument order for str_delimiter_pos_r()

#
# function str_to_array()
#
# Converts an simple string expression into an array.
# Supports simple syntax, nested arrays and nested PHP.
#
# @version 1.1
# @author  Wesley Roberts
# @date    July 11, 2010
# @link    http://fire.cowfight.com/
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

function str_to_array($str$var_sep=','$val_sep='=') {
	

	
# Defaults
	
if (!
is_string($str)) return null;
	
$r = array();
	

	
# Whitespace
	
$skip = array(" ","\t","\n","\r");
	

	
# Trim whitespace
	
$str trim($strimplode($skip));
	

	
# Remove array notation if necessary
	
# NOTE that trim will not work here
	
# AND they are individual on purpose
	
if (
substr($str,0,1) == '[')
	
	
$str substr($str,1);
	
if (
substr($str,-1,1) == ']')
	
	
$str substr($str,0,-1);
	

	
# Empty?
	
if (empty(
$str)) return array();
	

	
# Always end the string with $var_sep
	
$str.= $var_sep;
	
$len strlen($str);
	

	
# Defauts
	
$buf ''# buffer
	
$key 0;  # next array key
	
$inc 0;  # next numeric array key
	
$esc false# escaped char?
	

	
# Go through each character
	
for (
$i=0$i<$len$i++) :
	
	

	
	
# Skip escaped characters
	
	
if (
$esc) :
	
	
	
$buf .= $str[$i];
	
	
	
$esc false;
	
	
	
continue;
	
	
endif;
	
	

	
	
# Check the current character
	
	
switch(
$str[$i]):
	
	
	

	
	
	
# Association operator
	
	
	
case 
$val_sep:
	
	
	
	
if (!empty(
$buf)) :
	
	
	
	
	
$key $buf;
	
	
	
	
	
$buf '';
	
	
	
	
endif;
	
	
	
break;
	
	
	

	
	
	
# PHP! Note: this clears the buffer!!!
	
	
	
# If you need to prefix your results,
	
	
	
# do it within the braces.
	
	
	
case 
'{' :
	
	
	
	
$end str_delimiter_pos_r($str$i'{''}'$len);
	
	
	
	
$buf = eval(substr($str$i+1$end-$i-1)); // excluding braces
	
	
	
	
$i $end;
	
	
	
break;
	
	
	

	
	
	
# Sub-array notation is recursive
	
	
	
case 
'[':
	
	
	
	
$end str_delimiter_pos_r($str$i'['']'$len);
	
	
	
	
$buf str_to_array(substr($str$i$end-$i));
	
	
	
	
$i $end# will be incremented
	
	
	
break;
	
	
	

	
	
	
# Quotations to have spaces
	
	
	
case 
"'":
	
	
	
case 
'"':
	
	
	
	
$end str_delimiter_pos_r($str$i$str[$i], $str[$i], $len);
	
	
	
	
$buf substr($str$i+1$end-$i-1); // excluding quotes
	
	
	
	
$i $end;
	
	
	
break;
	
	
	

	
	
	
# Escape character
	
	
	
case 
'\\':
	
	
	
	
$esc true;
	
	
	
break;
	
	
	

	
	
	
# True
	
	
	
case 
't':
	
	
	
case 
'T':
	
	
	
	
$look_for 'true';
	
	
	
	
$look_len strlen($look_for);
	
	
	
	
if (
strtolower(substr($str$i$look_len)) == $look_for) :
	
	
	
	
	
$buf true;
	
	
	
	
	
$i += $look_len 1# this will be incremented
	
	
	
	
endif;
	
	
	
break;
	
	
	

	
	
	
# False
	
	
	
case 
'f':
	
	
	
case 
'F':
	
	
	
	
$look_for 'false';
	
	
	
	
$look_len strlen($look_for);
	
	
	
	
if (
strtolower(substr($str$i$look_len)) == $look_for) :
	
	
	
	
	
$buf false;
	
	
	
	
	
$i += $look_len 1# this will be incremented
	
	
	
	
endif;
	
	
	
break;
	
	
	

	
	
	
# Variable separator
	
	
	
case 
$var_sep :
	
	
	
	
$r[$key] = $buf;
	
	
	
	
if (
is_numeric($key))
	
	
	
	
	
$inc++;
	
	
	
	
$key $inc;
	
	
	
	
$buf '';
	
	
	
break;
	
	
	

	
	
	
# Default
	
	
	
default:
	
	
	
	
if (! 
in_array($str[$i], $skip))
	
	
	
	
	
$buf .= $str[$i];
	
	
	
break;
	
	

	
	
endswitch;
	

	
endfor;
	

	
# Return the final value
	
return 
$r;
}

# Looks for the closing delimiter ($rchar). 
# Assumes that the first char ($offset=0) is the opening delimiter ($lchar).
#
function str_delimiter_pos_r(&$str$offset=0$lchar='['$rchar=']', &$len=0) {
	
$r $offset+1;
	
for (
$r$r<$len$r++) :
	

	
	
# Escape character
	
	
if (
$str[$r] == '\\')
	
	
	
$r++;
	
	

	
	
# Sub delimiters
	
	
# (this only works when the delimiters are distinct)
	
	
elseif ((
$str[$r] == $lchar) && ($lchar != $rchar))
	
	
	
$r str_delimiter_pos_r($str$r$lchar$rchar$len);
	
	

	
	
# Whew. We made it.
	
	
elseif (
$str[$r] == $rchar)
	
	
	
return 
$r;
	
endfor;
	
return 
$len;
}


Offline jchookTopic starter

  • Irregular
  • Posts: 4
    • View Profile
Re: str_to_array - Convert a string to an array
« Reply #4 on: July 12, 2010, 02:07:56 AM »
New in Version 1.2
  • Now semi-whitespace-sensitve -- that is, whitespace is trimmed from the edges of values and keys. This greatly simplifies the syntax requirements and makes for generally easier writing and reading
  • Supports solo variables such as [ $var_name ]
  • Supports in-line variables wrapped in percent-signs such as %var_name%
  • Extracts additional variables to the local symbol table for use in building values or keys
  • Improved numeric key handling
  • Fixed poor support for true and false

The Code
#
# function str_to_array()
#
# Converts an simple string expression into an array.
# Supports simple syntax, nested arrays and nested PHP.
#
# @version 1.2
# @author  Wesley Roberts
# @date    July 11, 2010
# @link    http://fire.cowfight.com/
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

function str_to_array($str$opts=array()) {
	

	
# Defaults
	
if (!
is_string($str)) return null;
	
$r = array();
	
$default_opts = array(
	
	
'var_sep' => ',',
	
	
'val_sep' => '=',
	
	
'allow_eval' => true,
	
);
	
$opts array_merge($default_opts$opts);
	
extract($opts);
	

	
# Whitespace
	
$skip = array(" ","\t","\n","\r");
	

	
# Trim whitespace
	
$str trim($str);
	

	
# Remove array notation if necessary
	
# NOTE that trim will not work here
	
# AND they are individual on purpose
	
if (
substr($str,0,1) == '[')
	
	
$str substr($str,1);
	
if (
substr($str,-1) == ']')
	
	
$str substr($str,0,-1);
	

	

	
# Empty?
	
if (empty(
$str)) return array();
	

	
# Always end the string with $var_sep
	
$str.= $var_sep;
	
$len strlen($str);
	

	
# Defauts
	
$buf ''# buffer
	
$key 0;  # next array key
	
$inc 0;  # next numeric array key
	
$esc false# escaped char?
	
$quo false# quoted content? (i.e. can't be keyword)
	
$red false# have we read any non-space chars yet?
	

	
# Go through each character
	
for (
$i=0$i<$len$i++) :
	
	

	
	
# Skip escaped characters
	
	
if (
$esc) :
	
	
	
$buf .= $str[$i];
	
	
	
$esc false;
	
	
	
continue;
	
	
endif;
	
	

	
	
# Check the current character
	
	
switch(
$str[$i]):
	
	
	

	
	
	
# Association operator
	
	
	
case 
$val_sep:
	
	
	
	
if (!empty(
$buf)) :
	
	
	
	
	
$key trim($bufimplode($skip));
	
	
	
	
	
$red false;
	
	
	
	
	
$buf '';
	
	
	
	
endif;
	
	
	
break;
	
	
	

	
	
	
# PHP! Note: this clears the buffer!!!
	
	
	
# If you need to prefix your results,
	
	
	
# do it within the braces.
	
	
	
case 
'{' :
	
	
	
	
$end str_delimiter_pos_r($str$i'{''}'$len);
	
	
	
	
if (
$allow_eval):
	
	
	
	
	
$buf = eval(substr($str$i+1$end-$i-1)); // excluding braces
	
	
	
	
	
$i $end;
	
	
	
	
endif;
	
	
	
break;
	
	
	

	
	
	
# Sub-array notation is recursive
	
	
	
case 
'[':
	
	
	
	
$end str_delimiter_pos_r($str$i'['']'$len);
	
	
	
	
$buf str_to_array(substr($str$i$end-$i), $opts);
	
	
	
	
$i $end# will be incremented
	
	
	
break;
	
	
	

	
	
	
# Variables with %
	
	
	
case 
'%':
	
	
	
	
$end str_delimiter_pos_r($str$i'%''%'$len);
	
	
	
	
$var substr($str$i$end-$i);
	
	
	
	
$buf = $$var# variable variable
	
	
	
	
$i $end# will be incremented
	
	
	
break;
	
	
	

	
	
	
# Quotations allow spaces
	
	
	
case 
"'":
	
	
	
case 
'"':
	
	
	
	
$end str_delimiter_pos_r($str$i$str[$i], $str[$i], $len);
	
	
	
	
$buf substr($str$i+1$end-$i-1); // excluding quotes
	
	
	
	
$i $end;
	
	
	
	

	
	
	
	
# Double quotes can be evaluated
	
	
	
	
if (
$str[$i] == '"' && $allow_eval
	
	
	
	
	
$buf = eval('return "'.$buf.'";');
	
	
	
	
else  
$quo true# quoted
	
	
	
break;
	
	
	

	
	
	
# Escape character
	
	
	
case 
'\\':
	
	
	
	
$esc true;
	
	
	
break;
	
	
	

	
	
	
# Variable separator (i.e. clear buffer)
	
	
	
case 
$var_sep :
	
	
	
	

	
	
	
	
# Keywords are possible when the input
	
	
	
	
# is a single non-quoted word
	
	
	
	
if (!
$quo):
	
	
	
	
	
if (
$buf == 'true') :
	
	
	
	
	
	
$buf true;
	
	
	
	
	
elseif (
$buf == 'false') :
	
	
	
	
	
	
$buf false;
	
	
	
	
	
elseif (
$buf[0] == '$') :
	
	
	
	
	
	
$var substr($buf1);
	
	
	
	
	
	
$buf = $$var# variable variable
	
	
	
	
	
endif;
	
	
	
	

	
	
	
	
# If we're not in quotes, be more strict about
	
	
	
	
# whitespace, but allow it in the middle.
	
	
	
	
else : 
$buf rtrim($bufimplode($skip)); 
	
	
	
	
endif;
	
	
	
	

	
	
	
	
# If the key was an integer, then we need
	
	
	
	
# to find the next available integer for
	
	
	
	
# the next entry's key 
	
	
	
	
if (
is_int($key)) :
	
	
	
	
	
do { 
$inc++; } while(array_key_exists($inc$r));
	
	
	
	
endif;
	
	
	
	

	
	
	
	
# Dump buffer into the returned array
	
	
	
	
# associated with the appropriate key
	
	
	
	
$r[$key] = $buf;
	
	
	
	

	
	
	
	
# Prepare the next key
	
	
	
	
$key $inc;
	
	
	
	

	
	
	
	
# Clear the buffer for the next entry
	
	
	
	
$buf '';
	
	
	
	
$red false;
	
	
	
break;
	
	
	

	
	
	
# Default. If we have started reading content
	
	
	
# you can count in the spaces. Otherwise, f spaces
	
	
	
default:
	
	
	
	
if (
$red || !in_array($str[$i], $skip)) :
	
	
	
	
	
$red true;
	
	
	
	
	
$buf .= $str[$i];
	
	
	
	
endif;
	
	
	
break;
	
	

	
	
endswitch;
	

	
endfor;
	

	
# Return the final value
	
return 
$r;
}

# Looks for the closing delimiter ($rchar). 
# Assumes that the first char ($offset=0) is the opening delimiter ($lchar).
#
function str_delimiter_pos_r(&$str$offset=0$lchar='['$rchar=']', &$len=0) {
	
$r $offset+1;
	
for (
$r$r<$len$r++) :
	

	
	
# Escape character
	
	
if (
$str[$r] == '\\')
	
	
	
$r++;
	
	

	
	
# Sub delimiters
	
	
# (this only works when the delimiters are distinct)
	
	
elseif ((
$str[$r] == $lchar) && ($lchar != $rchar))
	
	
	
$r str_delimiter_pos_r($str$r$lchar$rchar$len);
	
	

	
	
# Whew. We made it.
	
	
elseif (
$str[$r] == $rchar)
	
	
	
return 
$r;
	
endfor;
	
return 
$len;
}



Demonstration of Improvements
Code: [Select]
# version 1.1 syntax
# version 1.2 syntax

[ "some long key" = "some long string" ]
[ some long key = some long string ]

[ { return $variable; } ]
[ $variable ]

[ { return "something with $variables"; } ]
[ something with %variables% ]
[ "something with $variables" ]
« Last Edit: July 12, 2010, 02:11:47 AM by jchook »