Return part of string in array - php

So I'm trying to make this little script work for fun and just cant get it to work,
I have an array of random names that are assigned their 'random' email addresses, I want to check if the email address have extension:
'#hotmail.com',
'#hotmail.ca', or
'#yahoo.ca' . if they are then echo something like 'Daniel, your email addresses extension is $extension, you qualify'
and if they don't just say 'Kayla, your email address is $extension, you don't qualify.
I want to add a foreach statement explaining that for each person in the array $ClassRoom2, i've tried using strstr() but it doesn't work inside the foreach because it can only have one string.
heres what i got so far:
qualify = "";
$ClassRoom2 = array(
'Daniel' => 'fresco#hotmail.com',
'Mike' => 'dkoko#yahoo.ca',
'Meranda' => 'brunnn_23#hotmail.ca',
'Will' => 'yumyum03#wp.pl',
'Brittey' => 's0sd#outlook.com',
'Kayla' => 'hocklife#freebie.com' );
switch ($ClassRoom2) {
case '#hotmail.com':
echo 'You are using extension '. $final; $qualify = 1; break;
case '#hotmail.ca':
echo 'You are using extension '. $final; $qualify = 1; break;
case '#yahoo.com':
echo 'You are using extension '. $final; $quality = 1; break;
case '#yahoo.ca':
echo 'You are using extension '. $final; $qualify = 1; break;
case '#live.ca':
echo 'You are using extension '. $final; $quality = 1; break;
default:
echo 'its something else'; $qualify = 0;
break;
}
if ($qualify == 1) {
echo "Congratulations, you quality for the contest. The extension you chose was <b>$final</b>";
} else {
echo "Sorry mate! you didn't quality for the contest.";
}

Use explode() to get the domain part and compare it
$parts = explode("#", "johndoe#domain.com");
echo ($parts[1]=='domain.com') ? 'qualify' : 'not qualify';

Sorry for my late reaction, I was still testing my code example.
If you want to stick with the switch you currently designed, you could use a simple preg_match to extract the string you need. Here is a little example (you can remove the comment and put in your switch there):
<?php
$ClassRoom2 = array(
'Daniel' => 'fresco#hotmail.com',
'Mike' => 'dkoko#yahoo.ca',
'Meranda' => 'brunnn_23#hotmail.ca',
'Will' => 'yumyum03#wp.pl',
'Brittey' => 's0sd#outlook.com',
'Kayla' => 'hocklife#freebie.com'
);
foreach ($ClassRoom2 as $name=>$email) {
$matches = [];
preg_match( "/(#.+)/", $email, $matches);
// Do things with $matches[0] here (your switch for eg)
// switch ($matches[0]) {
// case '#hotmail.com':
// ...
print '<br/> ' . $matches[0];
}
?>
If you want, you can fiddle arround with preg matches on this website: regexr
Update You can actually do a lot with preg_match, once you get the hang of it :)
foreach ($ClassRoom2 as $name=>$email) {
$matches = preg_match( "/#(hotmail.com|hotmail.ca|yahoo.ca|yahoo.com|live.ca)/", $email);
// if ($matches) // or simply replace the preg_match in the if
print '<br/> ' . $email . ($matches ? ' qualifies' : ' <strong>does not qualify</strong> ') . 'for the email test';
}

I would put the list of entries and the qualifying extensions on separate arrays then check each people entry and parse their information to see if each qualify, like this:
$peoplelist = array(
'Daniel' => 'fresco#hotmail.com',
'Mike' => 'dkoko#yahoo.ca',
'Meranda' => 'brunnn_23#hotmail.ca',
'Will' => 'yumyum03#wp.pl',
'Brittey' => 's0sd#outlook.com',
'Kayla' => 'hocklife#freebie.com'
);
$qualify = array(
'hotmail.com',
'hotmail.ca',
'yahoo.com',
'yahoo.ca',
'live.ca',
);
foreach( $peoplelist as $name => $email )
{
$parts = explode( "#", $email );
$extension = strtolower( trim( array_pop( $parts ) ) );
echo "Hi, ".$name.". You are using extension #".$extension.". <br /> \n";
if( in_array( $extension, $qualify ) )
{
echo "Congratulations, you quality for the contest. <br /> \n";
}
}

Related

check a string contains any word from array

i have a set of predefined array contains strings and words.I am trying to check whether my string contains at least one word from that array.
$array = array("PHP code tester Sandbox Online","abcd","defg" );
$string = 'code testy';//code is already in that array
i tried many ways,but not correct solution
first method
$i = count(array_intersect($array, explode(" ", preg_replace("/[^A-Za-z0-9' -]/", "", $string))));
echo ($i) ? "found ($i)" : "not found";
second method
if (stripos(json_encode($array),$string) !== false) { echo "found";}
else{ echo "not found";}
I suppose you are looking for a match which is any of the words.
$array = array("PHP code tester Sandbox Online","abcd","defg" );
$string = 'code|testy';
foreach ($array as $item ) {
if(preg_match("/\b{$string}\b/i", $item)) {
var_dump( $item );
}
}
You have to iterate over the array and test each one of the cases separately, first 'code', then 'testy', or whatever you want. If you json_encode, even if you trim both of strings to do this comparaison, the return will be not found.
But in the first string if you had like this
$array = array("PHP code testy Sandbox Online","abcd","defg" );
$string = 'code testy';//code is already in that array
you will get surely a "found" as return.
if (stripos(trim(json_encode($array)),trim($string)) !== false) { echo "found";}
else{ echo "not found";}
You could use explode() to get an array from the strings and then go through each of them.
$array = array("PHP code tester Sandbox Online","abcd","defg" );
$string = 'code testy';
foreach(explode(' ', $string) as $key => $value) {
foreach($array as $arrKey => $arrVal) {
foreach(explode(' ', $arrVal) as $key => $str) {
if ($value == $str) {
echo $str . ' is in array';
}
}
}
}

split full email addresses into name and email?

There seems to be many acceptable email address formats in the To: and From: raw email headers ...
person#place.com
person <person#place.com>
person
Another Person <person#place.com>
'Another Person' <person#place.com>
"Another Person" <person#place.com>
After not finding any effective PHP functions for splitting out names and addresses, I've written the following code.
You can DEMO IT ON CODEPAD to see the output...
// validate email address
function validate_email( $email ){
return (filter_var($email, FILTER_VALIDATE_EMAIL)) ? true : false;
}
// split email into name / address
function email_split( $str ){
$name = $email = '';
if (substr($str,0,1)=='<') {
// first character = <
$email = str_replace( array('<','>'), '', $str );
} else if (strpos($str,' <') !== false) {
// possibly = name <email>
list($name,$email) = explode(' <',$str);
$email = str_replace('>','',$email);
if (!validate_email($email)) $email = '';
$name = str_replace(array('"',"'"),'',$name);
} else if (validate_email($str)) {
// just the email
$email = $str;
} else {
// unknown
$name = $str;
}
return array( 'name'=>trim($name), 'email'=>trim($email) );
}
// test it
$tests = array(
'person#place.com',
'monarch <themonarch#tgoci.com>',
'blahblah',
"'doc venture' <doc#venture.com>"
);
foreach ($tests as $test){
echo print_r( email_split($test), true );
}
Am I missing anything here? Can anyone recommend a better way?
I have managed to make one regex to your test cases:
person#place.com
person <person#place.com>
person
Another Person <person#place.com>
'Another Person' <person#place.com>
"Another Person" <person#place.com>
using preg_match with this regex will surely help you bit.
function email_split( $str ){
$sPattern = "/([\w\s\'\"]+[\s]+)?(<)?(([\w-\.]+)#((?:[\w]+\.)+)([a-zA-Z]{2,4}))?(>)?/g";
preg_match($sPattern,$str,$aMatch);
if(isset($aMatch[1]))
{
echo $aMatch[1] //this is name;
}
if(isset($aMatch[3]))
{
echo $aMatch[3] //this is EmailAddress;
}
}
Note: I just noticed that single "person" i.e. your third test case could be discarded with this regex (just that because of space constraint in regex) so,at first line of your email_split function, append space at last place of your string.
Then it would be bang on target.
Thanks, Hope this helps.
Code I tried:
<?php
// validate email address
function validate_email($email) {
return (filter_var($email, FILTER_VALIDATE_EMAIL)) ? true : false;
}
// split email into name / address
function email_split($str) {
$str .=" ";
$sPattern = '/([\w\s\'\"]+[\s]+)?(<)?(([\w-\.]+)#((?:[\w]+\.)+)([a-zA-Z]{2,4}))?(>)?/';
preg_match($sPattern, $str, $aMatch);
//echo "string";
//print_r($aMatch);
$name = (isset($aMatch[1])) ? $aMatch[1] : '';
$email = (isset($aMatch[3])) ? $aMatch[3] : '';
return array('name' => trim($name), 'email' => trim($email));
}
// test it
$tests = array(
'person#place.com',
'monarch <themonarch#tgoci.com>',
'blahblah',
"'doc venture' <doc#venture.com>"
);
foreach ($tests as $test) {
echo "<pre>";
echo print_r(email_split($test), true);
echo "</pre>";
}
Output I got:
Array
(
[name] =>
[email] => person#place.com
)
Array
(
[name] => monarch
[email] => themonarch#tgoci.com
)
Array
(
[name] => blahblah
[email] =>
)
Array
(
[name] => 'doc venture'
[email] => doc#venture.com
)
How about this:
function email_split($str) {
$parts = explode(' ', trim($str));
$email = trim(array_pop($parts), "<> \t\n\r\0\x0B");
$name = trim(implode(' ', $parts), "\"\' \t\n\r\0\x0B");
if ($name == "" && strpos($email, "#") === false) { // only single string - did not contain '#'
$name = $email;
$email = "";
}
return array('name' => $name, 'email' => $email);
}
Looks like this is about twice as fast as the regex solution.
Note: the OPs third test case (for my purposes) is not needed. But in the interest of answering the OP I added the if stmt to produce the OPs expected results. This could have been done other ways (check the last element of $parts for '#').
use preg_match in php, http://php.net/manual/en/function.preg-match.php
or in my opinion, you can make your own function (let say get_email_address), it catch # character and then get the 'rest-left-string' from # until '<' character and 'rest-right-string' from # until '>' character.
for example, string monarch <themonarch#tgoci.com> will return 'rest-left-string' = themonarch and 'rest-right-string' = tgoci.com . finally, your function get_email_address will return themonarch#tgoci.com
hopefully it help.. :)
unfortunately the regex fails in a couple of conditions of the fullname:
non alphanumeric chars (eg. "Amazon.it")
non printable chars
emojs
i adjusted the expression this way
$sPattern = '/([^<]*)?(<)?(([\w-\.]+)#((?:[\w]+\.)+)([a-zA-Z]{2,4}))?(>)?/';
and now all chars are correctly recognized and splitted.
tested with
$address = "Test User # `` . !! 🔥 <test#email.com";
after 7 years, hope this helps :)

Parse Wordpress like Shortcode

I want to parse shortcode like Wordpress with attributes:
Input:
[include file="header.html"]
I need output as array, function name "include" and attributes with values as well , any help will be appreciated.
Thanks
Here's a utility class that we used on our project
It will match all shortcodes in a string (including html) and it will output an associative array including their name, attributes and content
final class Parser {
// Regex101 reference: https://regex101.com/r/pJ7lO1
const SHORTOCODE_REGEXP = "/(?P<shortcode>(?:(?:\\s?\\[))(?P<name>[\\w\\-]{3,})(?:\\s(?P<attrs>[\\w\\d,\\s=\\\"\\'\\-\\+\\#\\%\\!\\~\\`\\&\\.\\s\\:\\/\\?\\|]+))?(?:\\])(?:(?P<content>[\\w\\d\\,\\!\\#\\#\\$\\%\\^\\&\\*\\(\\\\)\\s\\=\\\"\\'\\-\\+\\&\\.\\s\\:\\/\\?\\|\\<\\>]+)(?:\\[\\/[\\w\\-\\_]+\\]))?)/u";
// Regex101 reference: https://regex101.com/r/sZ7wP0
const ATTRIBUTE_REGEXP = "/(?<name>\\S+)=[\"']?(?P<value>(?:.(?![\"']?\\s+(?:\\S+)=|[>\"']))+.)[\"']?/u";
public static function parse_shortcodes($text) {
preg_match_all(self::SHORTOCODE_REGEXP, $text, $matches, PREG_SET_ORDER);
$shortcodes = array();
foreach ($matches as $i => $value) {
$shortcodes[$i]['shortcode'] = $value['shortcode'];
$shortcodes[$i]['name'] = $value['name'];
if (isset($value['attrs'])) {
$attrs = self::parse_attrs($value['attrs']);
$shortcodes[$i]['attrs'] = $attrs;
}
if (isset($value['content'])) {
$shortcodes[$i]['content'] = $value['content'];
}
}
return $shortcodes;
}
private static function parse_attrs($attrs) {
preg_match_all(self::ATTRIBUTE_REGEXP, $attrs, $matches, PREG_SET_ORDER);
$attributes = array();
foreach ($matches as $i => $value) {
$key = $value['name'];
$attributes[$i][$key] = $value['value'];
}
return $attributes;
}
}
print_r(Parser::parse_shortcodes('[include file="header.html"]'));
Output:
Array
(
[0] => Array
(
[shortcode] => [include file="header.html"]
[name] => include
[attrs] => Array
(
[0] => Array
(
[file] => header.html
)
)
)
)
Using this function
$code = '[include file="header.html"]';
$innerCode = GetBetween($code, '[', ']');
$innerCodeParts = explode(' ', $innerCode);
$command = $innerCodeParts[0];
$attributeAndValue = $innerCodeParts[1];
$attributeParts = explode('=', $attributeAndValue);
$attribute = $attributeParts[0];
$attributeValue = str_replace('"', '', $attributeParts[1]);
echo $command . ' ' . $attribute . '=' . $attributeValue;
//this will result in include file=header.html
$command will be "include"
$attribute will be "file"
$attributeValue will be "header.html"
I also needed this functionality in my PHP framework. This is what I've written, it works pretty well. It works with anonymous functions, which I really like (it's a bit like the callback functions in JavaScript).
<?php
//The content which should be parsed
$content = '<p>Hello, my name is John an my age is [calc-age day="4" month="10" year="1991"].</p>';
$content .= '<p>Hello, my name is Carol an my age is [calc-age day="26" month="11" year="1996"].</p>';
//The array with all the shortcode handlers. This is just a regular associative array with anonymous functions as values. A very cool new feature in PHP, just like callbacks in JavaScript or delegates in C#.
$shortcodes = array(
"calc-age" => function($data){
$content = "";
//Calculate the age
if(isset($data["day"], $data["month"], $data["year"])){
$age = date("Y") - $data["year"];
if(date("m") < $data["month"]){
$age--;
}
if(date("m") == $data["month"] && date("d") < $data["day"]){
$age--;
}
$content = $age;
}
return $content;
}
);
//http://stackoverflow.com/questions/18196159/regex-extract-variables-from-shortcode
function handleShortcodes($content, $shortcodes){
//Loop through all shortcodes
foreach($shortcodes as $key => $function){
$dat = array();
preg_match_all("/\[".$key." (.+?)\]/", $content, $dat);
if(count($dat) > 0 && $dat[0] != array() && isset($dat[1])){
$i = 0;
$actual_string = $dat[0];
foreach($dat[1] as $temp){
$temp = explode(" ", $temp);
$params = array();
foreach ($temp as $d){
list($opt, $val) = explode("=", $d);
$params[$opt] = trim($val, '"');
}
$content = str_replace($actual_string[$i], $function($params), $content);
$i++;
}
}
}
return $content;
}
echo handleShortcodes($content, $shortcodes);
?>
The result:
Hello, my name is John an my age is 22.
Hello, my name is Carol an my age is 17.
This is actually tougher than it might appear on the surface. Andrew's answer works, but begins to break down if square brackets appear in the source text [like this, for example]. WordPress works by pre-registering a list of valid shortcodes, and only acting on text inside brackets if it matches one of these predefined values. That way it doesn't mangle any regular text that might just happen to have a set of square brackets in it.
The actual source code of the WordPress shortcode engine is fairly robust, and it doesn't look like it would be all that tough to modify the file to run by itself -- then you could use that in your application to handle the tough work. (If you're interested, take a look at get_shortcode_regex() in that file to see just how hairy the proper solution to this problem can actually get.)
A very rough implementation of your question using the WP shortcodes.php would look something like:
// Define the shortcode
function inlude_shortcode_func($attrs) {
$data = shortcode_atts(array(
'file' => 'default'
), $attrs);
return "Including File: {$data['file']}";
}
add_shortcode('include', 'inlude_shortcode_func');
// And then run your page content through the filter
echo do_shortcode('This is a document with [include file="header.html"] included!');
Again, not tested at all, but it's not a very hard API to use.
I have modified above function with wordpress function
function extractThis($short_code_string) {
$shortocode_regexp = "/(?P<shortcode>(?:(?:\\s?\\[))(?P<name>[\\w\\-]{3,})(?:\\s(?P<attrs>[\\w\\d,\\s=\\\"\\'\\-\\+\\#\\%\\!\\~\\`\\&\\.\\s\\:\\/\\?\\|]+))?(?:\\])(?:(?P<content>[\\w\\d\\,\\!\\#\\#\\$\\%\\^\\&\\*\\(\\\\)\\s\\=\\\"\\'\\-\\+\\&\\.\\s\\:\\/\\?\\|\\<\\>]+)(?:\\[\\/[\\w\\-\\_]+\\]))?)/u";
preg_match_all($shortocode_regexp, $short_code_string, $matches, PREG_SET_ORDER);
$shortcodes = array();
foreach ($matches as $i => $value) {
$shortcodes[$i]['shortcode'] = $value['shortcode'];
$shortcodes[$i]['name'] = $value['name'];
if (isset($value['attrs'])) {
$attrs = shortcode_parse_atts($value['attrs']);
$shortcodes[$i]['attrs'] = $attrs;
}
if (isset($value['content'])) {
$shortcodes[$i]['content'] = $value['content'];
}
}
return $shortcodes;
}
I think this one help for all :)
Updating the #Duco's snippet, As it seems like, it's exploding by spaces which ruins when we have some like
[Image source="myimage.jpg" alt="My Image"]
To current one:
function handleShortcodes($content, $shortcodes){
function read_attr($attr) {
$atList = [];
if (preg_match_all('/\s*(?:([a-z0-9-]+)\s*=\s*"([^"]*)")|(?:\s+([a-z0-9-]+)(?=\s*|>|\s+[a..z0-9]+))/i', $attr, $m)) {
for ($i = 0; $i < count($m[0]); $i++) {
if ($m[3][$i])
$atList[$m[3][$i]] = null;
else
$atList[$m[1][$i]] = $m[2][$i];
}
}
return $atList;
}
//Loop through all shortcodes
foreach($shortcodes as $key => $function){
$dat = array();
preg_match_all("/\[".$key."(.*?)\]/", $content, $dat);
if(count($dat) > 0 && $dat[0] != array() && isset($dat[1])){
$i = 0;
$actual_string = $dat[0];
foreach($dat[1] as $temp){
$params = read_attr($temp);
$content = str_replace($actual_string[$i], $function($params), $content);
$i++;
}
}
}
return $content;
}
$content = '[image source="one" alt="one two"]';
Result:
array(
[source] => myimage.jpg,
[alt] => My Image
)
Updated (Feb 11, 2020)
It appears to be following regex under preg_match only identifies shortcode with attributes
preg_match_all("/\[".$key." (.+?)\]/", $content, $dat);
to make it work with as normal [contact-form] or [mynotes]. We can change the following to
preg_match_all("/\[".$key."(.*?)\]/", $content, $dat);
I just had the same problem. For what I have to do, I am going to take advantage of existing xml parsers instead of writing my own regex. I am sure there are cases where it won't work
example.php
<?php
$file_content = '[include file="header.html"]';
// convert the string into xml
$xml = str_replace("[", "<", str_replace("]", "/>", $file_content));
$doc = new SimpleXMLElement($xml);
echo "name: " . $doc->getName() . "\n";
foreach($doc->attributes() as $key => $value) {
echo "$key: $value\n";
}
$ php example.php
name: include
file: header.html
to make it work on ubuntu I think you have to do this
sudo apt-get install php-xml
(thanks https://drupal.stackexchange.com/a/218271)
If you have lots of these strings in a file, then I think you can still do the find replace, and then just treat it all like xml.

vsprintf or sprintf with named arguments, or simple template parsing in PHP

I'm searching for a way to use named arguments for sprintf or printf.
Example:
sprintf(
'Last time logged in was %hours hours,
%minutes minutes, %seconds seconds ago'
,$hours,$minutes, $seconds
);
or via vsprintf and an associative array.
I have found some coding examples here
function sprintfn ($format, array $args = array())
http://php.net/manual/de/function.sprintf.php
and here
function vnsprintf( $format, array $data)
http://php.net/manual/de/function.vsprintf.php
where people wrote their own solutions.
But my question is, is there maybe an standard PHP solution out there to achieve this or is there another way, maybe with a simple PHP templating provided by PEAR, that I can achieve this by sticking to standard PHP?
Thanks for any help.
Late to the party, but you can simply use strtr to "translate characters or replace substrings"
<?php
$hours = 2;
$minutes = 24;
$seconds = 35;
// Option 1: Replacing %variable
echo strtr(
'Last time logged in was %hours hours, %minutes minutes, %seconds seconds ago',
[
'%hours' => $hours,
'%minutes' => $minutes,
'%seconds' => $seconds
]
);
// Option 2: Alternative replacing {variable}
echo strtr(
'Last time logged in was {hours} hours, {minutes} minutes, {seconds} seconds ago',
[
'{hours}' => $hours,
'{minutes}' => $minutes,
'{seconds}' => $seconds
]
);
// Option 3: Using an array with variables:
$data = [
'{hours}' => 2,
'{minutes}' => 24,
'{seconds}' => 35,
];
echo strtr('Last time logged in was {hours} hours, {minutes} minutes, {seconds} seconds ago', $data);
// More options: Of course you can replace any string....
outputs the following:
Last time logged in was 2 hours, 24 minutes, 35 seconds ago
I've written a small component exactly for this need. It's called StringTemplate.
With it you can get what you want with a code like this:
$engine = new StringTemplate\Engine;
$engine->render(
'Last time logged in was {hours} hours, {minutes} minutes, {seconds} seconds ago',
[
'hours' => '08',
'minutes' => 23,
'seconds' => 12,
]
);
//Prints "Last time logged in was 08 hours, 23 minutes, 12 seconds ago"
Hope that can help.
As far as I know printf/sprintf does not accept assoc arrays.
However it is possible to do printf('%1$d %1$d', 1);
Better than nothing ;)
This is from php.net
function vnsprintf( $format, array $data)
{
preg_match_all( '/ (?<!%) % ( (?: [[:alpha:]_-][[:alnum:]_-]* | ([-+])? [0-9]+ (?(2) (?:\.[0-9]+)? | \.[0-9]+ ) ) ) \$ [-+]? \'? .? -? [0-9]* (\.[0-9]+)? \w/x', $format, $match, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
$offset = 0;
$keys = array_keys($data);
foreach( $match as &$value )
{
if ( ( $key = array_search( $value[1][0], $keys, TRUE) ) !== FALSE || ( is_numeric( $value[1][0] ) && ( $key = array_search( (int)$value[1][0], $keys, TRUE) ) !== FALSE) )
{
$len = strlen( $value[1][0]);
$format = substr_replace( $format, 1 + $key, $offset + $value[1][1], $len);
$offset -= $len - strlen( 1 + $key);
}
}
return vsprintf( $format, $data);
}
Example:
$example = array(
0 => 'first',
'second' => 'second',
'third',
4.2 => 'fourth',
'fifth',
-6.7 => 'sixth',
'seventh',
'eighth',
'9' => 'ninth',
'tenth' => 'tenth',
'-11.3' => 'eleventh',
'twelfth'
);
echo vnsprintf( '%1$s %2$s %3$s %4$s %5$s %6$s %7$s %8$s %9$s %10$s %11$s %12$s<br />', $example); // acts like vsprintf
echo vnsprintf( '%+0$s %second$s %+1$s %+4$s %+5$s %-6.5$s %+6$s %+7$s %+9$s %tenth$s %-11.3$s %+10$s<br />', $example);
Example 2:
$examples = array(
2.8=>'positiveFloat', // key = 2 , 1st value
-3=>'negativeInteger', // key = -3 , 2nd value
'my_name'=>'someString' // key = my_name , 3rd value
);
echo vsprintf( "%%my_name\$s = '%my_name\$s'\n", $examples); // [unsupported]
echo vnsprintf( "%%my_name\$s = '%my_name\$s'\n", $examples); // output : "someString"
echo vsprintf( "%%2.5\$s = '%2.5\$s'\n", $examples); // [unsupported]
echo vnsprintf( "%%2.5\$s = '%2.5\$s'\n", $examples); // output : "positiveFloat"
echo vsprintf( "%%+2.5\$s = '%+2.5\$s'\n", $examples); // [unsupported]
echo vnsprintf( "%%+2.5\$s = '%+2.5\$s'\n", $examples); // output : "positiveFloat"
echo vsprintf( "%%-3.2\$s = '%-3.2\$s'\n", $examples); // [unsupported]
echo vnsprintf( "%%-3.2\$s = '%-3.2\$s'\n", $examples); // output : "negativeInteger"
echo vsprintf( "%%2\$s = '%2\$s'\n", $examples); // output : "negativeInteger"
echo vnsprintf( "%%2\$s = '%2\$s'\n", $examples); // output : [= vsprintf]
echo vsprintf( "%%+2\$s = '%+2\$s'\n", $examples); // [unsupported]
echo vnsprintf( "%%+2\$s = '%+2\$s'\n", $examples); // output : "positiveFloat"
echo vsprintf( "%%-3\$s = '%-3\$s'\n", $examples); // [unsupported]
echo vnsprintf( "%%-3\$s = '%-3\$s'\n", $examples); // output : "negativeInteger"
I know this has been resolved for too long now, but maybe my solution is simple enough, yet useful for somebody else.
With this little function you can mimic a simple templating system:
function parse_html($html, $args) {
foreach($args as $key => $val) $html = str_replace("#[$key]", $val, $html);
return $html;
}
Use it like this:
$html = '<h1>Hello, #[name]</h1>';
$args = array('name' => 'John Appleseed';
echo parse_html($html,$args);
This would output:
<h1>Hello, John Appleseed</h1>
Maybe not for everyone and every case, but it saved me.
See drupal's implementation
https://api.drupal.org/api/drupal/includes%21bootstrap.inc/function/format_string/7
It's simple and doesn't use regexp
function format_string($string, array $args = array()) {
// Transform arguments before inserting them.
foreach ($args as $key => $value) {
switch ($key[0]) {
case '#':
// Escaped only.
$args[$key] = check_plain($value);
break;
case '%':
default:
// Escaped and placeholder.
$args[$key] = drupal_placeholder($value);
break;
case '!':
// Pass-through.
}
}
return strtr($string, $args);
}
function drupal_placeholder($text) {
return '<em class="placeholder">' . check_plain($text) . '</em>';
}
Example:
$unformatted = 'Hello, #name';
$formatted = format_string($unformatted, array('#name' => 'John'));
This is what I'm using:
$arr = ['a' => 'happy','b' => 'funny'];
$templ = "I m a [a] and [b] person";
$r = array_walk($arr,function($i,$k) use(&$templ){
$templ = str_replace("[$k]",$i,$templ);
} );
var_dump($templ);
Since 5.3 because of the use keyword:
This function supports formatting {{var}} or {{dict.key}}, you can change the {{}} to {} etc to match you favor.
function formatString($str, $data) {
return preg_replace_callback('#{{(\w+?)(\.(\w+?))?}}#', function($m) use ($data){
return count($m) === 2 ? $data[$m[1]] : $data[$m[1]][$m[3]];
}, $str);
}
Example:
$str = "This is {{name}}, I am {{age}} years old, I have a cat called {{pets.cat}}.";
$dict = [
'name' => 'Jim',
'age' => 20,
'pets' => ['cat' => 'huang', 'dog' => 'bai']
];
echo formatString($str, $dict);
Output:
This is Jim, I am 20 years old, I have a cat called huang.
This is really the best way to go imho. No cryptic characters, just use the key names!
As taken from the php site:
http://www.php.net/manual/en/function.vsprintf.php
function dsprintf() {
$data = func_get_args(); // get all the arguments
$string = array_shift($data); // the string is the first one
if (is_array(func_get_arg(1))) { // if the second one is an array, use that
$data = func_get_arg(1);
}
$used_keys = array();
// get the matches, and feed them to our function
$string = preg_replace('/\%\((.*?)\)(.)/e',
'dsprintfMatch(\'$1\',\'$2\',\$data,$used_keys)',$string);
$data = array_diff_key($data,$used_keys); // diff the data with the used_keys
return vsprintf($string,$data); // yeah!
}
function dsprintfMatch($m1,$m2,&$data,&$used_keys) {
if (isset($data[$m1])) { // if the key is there
$str = $data[$m1];
$used_keys[$m1] = $m1; // dont unset it, it can be used multiple times
return sprintf("%".$m2,$str); // sprintf the string, so %s, or %d works like it should
} else {
return "%".$m2; // else, return a regular %s, or %d or whatever is used
}
}
$str = <<<HITHERE
Hello, %(firstName)s, I know your favorite PDA is the %(pda)s. You must have bought %(amount)s
HITHERE;
$dataArray = array(
'pda' => 'Newton 2100',
'firstName' => 'Steve',
'amount' => '200'
);
echo dsprintf($str, $dataArray);
// Hello, Steve, I know your favorite PDA is the Newton 2100. You must have bought 200
You'll want to avoid using % in you custom functions as it can interfere with other implementations, for example, date formatting in SQL, so...
function replace(string $string, iterable $replacements): string
{
return str_replace(
array_map(
function($k) {
return sprintf("{%s}", $k);
},
array_keys($replacements)
),
array_values($replacements),
$string
);
}
$string1 = 'Mary had a little {0}. Its {1} was white as {2}.';
echo replace($string1, ['lamb', 'fleece', 'snow']);
$string2 = 'Mary had a little {animal}. Its {coat} was white as {color}.';
echo replace($string2, ['animal' => 'lamb', 'coat' => 'fleece', 'color' => 'snow']);
$string1: Mary had a little lamb. Its fleece was white as snow.
$string2: Mary had a little lamb. Its fleece was white as snow.

Preparing a multi-dimensional array for an ExtJS tree control

please dont close this question as repeated one..........
I am new to php.
I am developing one tree grid in extjs.were i need to display field in tree format.so for front end i need to send the encoded data.
I want 2 functions for encoding and decoding a string variable,multidimensional array,variables with a set of delimiters.
For example if i am having an array.........
array(
array( "task" => "rose",
"duration" => 1.25,
"user" => 15
),
array( "task" => "daisy",
"duration" => 0.75,
"user" => 25,
),
array( "task" => "orchid",
"duration" => 1.15,
"user" => 7
),
array( "task" => "sunflower",
"duration" => 1.50,
"user" => 70
)
);
i want to encode all the array fields or single field as..........
array(
array( "task" => "rose",
"duration" => 1.25,
"user" => 15
),
array( "task" => "daisy",
"duration" => 0.75,
"user" => 25$sbaa,
),
array( "task" => "orchid",
"duration" => 1.15,
"user" => 7$!ass,
),
array( "task" => "sunflower",
"duration" => 1.50,
"user" => 70$!abc
)
);
So like this only i need to encode string,variables with delimiters.........
later all the encoded values to be decoded before its taken back to back end.....for this i have to use this plugin..........
encode.class.php...........
<?php
/*-------------------------
Author: Jonathan Pulice
Date: July 26th, 2005
Name: JPEncodeClass v1
Desc: Encoder and decoder using patterns.
-------------------------*/
class Protector
{
var $Pattern = "";
var $PatternFlip = "";
var $ToEncode = "";
var $ToDecode = "";
var $Decoded = "";
var $Encoded = "";
var $Bug = false;
var $DecodePattern = "";
function Debug($on = true)
{
$this->Bug = $on;
}
function Encode()
{
$ar = explode(":", $this->Pattern);
$enc = $this->ToEncode;
if ($this->Bug) echo "<!-- BEGIN ENCODING -->\n";
foreach ($ar as $num => $ltr)
{
switch ($ltr)
{
case "E":
$enc = base64_encode($enc);
break;
case "D":
$enc = base64_decode($enc);
break;
case "R":
$enc = strrev($enc);
break;
case "I":
$enc = $this->InvertCase($enc);
break;
}
if ($this->Bug) echo "<!-- {$ltr}: {$enc} -->\n";
}
if ($this->Bug) echo "<!-------------------->\n\n";
#$this->Encoded = ($enc == $this->Str) ? "<font color='red'>No Encoding/Decoding Pattern Detected!</font>" : $enc;
return $this->Encoded;
}
function Decode()
{
$pattern = ($this->DecodePattern != "") ? $this->DecodePattern : $this->Pattern;
//Reverse the pattern
$this->PatternFlip($pattern);
//make into an array
$ar = explode(":", $this->PatternFlip);
$t = ($this->Encoded == "") ? $this->ToDecode : $this->Encoded;
if ($this->Bug) echo "<!-- BEGIN DECODING -->\n";
foreach ($ar as $num => $ltr)
{
switch ($ltr)
{
case "E":
$t = base64_encode($t);
break;
case "D":
$t = base64_decode($t);
break;
case "R":
$t = strrev($t);
break;
case "I":
$t = $this->InvertCase($t);
break;
}
if ($this->Bug) echo "<!-- {$ltr}: {$t} -->\n";
}
if ($this->Bug) echo "<!-------------------->\n\n";
$this->Decoded = ($t == $this->Encoded) ? "<font color='red'>No Encoding/Decoding Pattern Detected!</font>" : $t;
return $this->Decoded;
}
function MakePattern($len = 10)
{
//possible letters
// E - Base64 Encode
// R - Reverse String
// I - Inverse Case
$poss = array('E','R', 'I');
//generate a string
for ( $i = 0 ; $i < $len ; $i++ )
{
$tmp[] = $poss[ rand(0,2) ];
}
//echo $str. "<br>";
//fix useless pattern section RR II
$str = implode(":", $tmp);
//fix
$str = str_replace( 'R:R:R:R:R:R' , 'R:E:R:E:R:E' , $str );
$str = str_replace( 'R:R:R:R:R' , 'R:E:R:E:R' , $str );
$str = str_replace( 'R:R:R:R' , 'R:E:R:E' , $str );
$str = str_replace( 'R:R:R' , 'R:E:R' , $str );
$str = str_replace( 'R:R' , 'R:E' , $str );
//fix
$str = str_replace( 'I:I:I:I:I:I' , 'I:E:I:E:I:E' , $str );
$str = str_replace( 'I:I:I:I:I' , 'I:E:I:E:I' , $str );
$str = str_replace( 'I:I:I:I' , 'I:E:I:E' , $str );
$str = str_replace( 'I:I:I' , 'I:E:I' , $str );
$str = str_replace( 'I:I' , 'I:E' , $str );
//string is good, set as pattern
$this->Pattern = $str;
return $this->Pattern; //if we need it
}
function PatternFlip($pattern)
{
//reverse the pattern
$str = strrev($pattern);
$ar = explode(":", $str);
foreach ($ar as $num => $ltr)
{
switch ($ltr)
{
case "E":
$tmp[] = "D";
break;
case "D":
$tmp[] = "E";
break;
case "R":
$tmp[] = "R";
break;
case "I":
$tmp[] = "I";
break;
}
}
$rev = implode(":", $tmp);
$this->PatternFlip = $rev;
return $this->PatternFlip;
}
// This is my custom Case Invertor!
// if you would like to use this in a script, please credit it to me, thank you
function InvertCase($str)
{
//Do initial conversion
$new = strtoupper( $str );
//spluit into arrays
$s = str_split( $str );
$n = str_split( $new );
//now we step through each letter, and if its the same as before, we swap it out
for ($i = 0; $i < count($s); $i++)
{
if ( $s[$i] === $n[$i] ) //SWAP THE LETTER
{
//ge the letter
$num = ord( $n[$i] );
//see if the ord is in the alpha ranges ( 65 - 90 | 97 - 122 )
if ( ( $num >= 65 AND $num <= 90 ) OR ( $num >= 97 AND $num <= 122 ) )
{
if ($num < 97 ) { $num = $num + 32; }
else { $num = $num - 32; }
$newchr = chr($num);
$n[$i] = $newchr;
}
}
}
//join the new string back together
$newstr = implode("", $n);
return $newstr;
}
}
?>
............
from this plugin i need to use encode and decode functions for my functions.........
if anyone can help me on this.......it will be very much useful for me.......
Why don't you use json_encode? Just do
$str=json_encode($array);
Then, send the data, and at the other end do
$array=json_decode($str);
Okay, let's break down the problem.
You have an array. Each element in the array is a hash. One (or more) of the values in that hash has to be encoded using that horrible abomination of a library. But the library can't process arrays.
We'll have to process the array ourselves.
<rant>
Before we begin, I'd just like to again express how horribly that "Protector" code is designed. It's written for PHP4 and is effectively spaghetti code wrapped in a class. It mis-uses properties, almost as if the user had some sort of mis-remembering about how Java's instance variables work and somehow thought it would be appropriate or sane to use PHP in the same way. If the author of the code doesn't look back on that revolting chunk of bytes now with utter disdain, something is severely wrong with him.
</rant>
I'm going to base my knowledge of this class on this copy of it, as the one you've provided is formatted even worse than the original.
First, let's create a list of inner array keys that we need to encode.
$keys_to_encode = array( 'user' );
Your example encoding lists only the user key as encodable. If you need to encode others, just add more elements to that array.
Now, let's prepare our "Protector." It seems to want you to either specify a pattern, or use the MakePattern method to have it create one. We're going to manually-specify one because MakePattern can come up with effectively useless combinations.
$stupid = new Protector();
$stupid->Pattern = 'E:I:E:R:D:I:E';
This will base64-encode, flip the case, base64 again, reverse it, un-base64, flip the case, and then re-base64. Be aware that PHP's base64 decoder "correctly" ignores bad padding and unexpected characters, which is the only reason the base64-reverse-unbase64 thing will work. The resulting string will look like gibberish to people that don't know what base64 looks like, and un-base64 to gibberish for people that to know what base64 looks like.
If you need to encode the values in a certain way, you'd do so by just changing the pattern. It's important that you either hard-code the pattern or store it somewhere with the data, because without it, you'll have a hard time doing the decode. (I mean, it can be done by hand, but you don't want to have to do that.) I expect that your boss is going to give you specific instructions on the pattern, given that you don't have an option in using this utter failure at a class.
Now it's time to process our data. Let's pretend that $in contains your original array.
$out = array();
foreach($in as $k => $target) {
foreach($keys_to_encode as $target_key) {
$stupid->ToEncode = $target[ $target_key ];
$target[ $target_key ] = $stupid->Encode();
}
$out[$k] = $target;
}
This loops through the array of hashes, then inside each hash, only the keys we want to encode are encoded. The encoded hash is placed in a new array, $out. This is what you'd pass to your tree widget.
Decoding is just as easy. You've stated that your goal is letting users edit certain data in the tree widget, and you seem to want to protect the underlying keys. This tells me that you probably only need to deal with one of the hashes at a time. Therefore, I'm going to write this decode sample using only one value, $whatever.
$stupidest = new Protector();
$stupidest->Pattern = 'E:I:E:R:D:I:E'; // SAME PATTERN!
$stupidest->ToDecode = $whatever;
$decoded = $stupidest->Decode();
Again, it's critical that you use the same decode pattern here.
As for the actual interaction with the tree widget, you're on your own there. I know only enough about ExtJS to know that it exists and that the GUI creators for it are really fun to play with.

Categories