Generic PHP Match Template with String - php

is there a function that will allow me to do the following:
$template = "{name}:{city}-{state}"
$string = "Tom:Some CityPlace-CA"
$out = function_I_am_looking_for($template,$string);
when $out returns
Array(
[name] => Tom
[city] => Some CityPlace
[state] => CA
)
Does such a function exist?
-------- EDIT -----------
So the people have spoken, and since I dont like seeing something like this die, I will conclude. No built in function exists, however I did mock up one, and it does work. Feel free to refine, please comment you edits.
function genaric_match($template,$string,$varStart="{{",$varEnd="}}"){
$template = str_replace($varStart,"|~|`",$template);
$template = str_replace($varEnd,"`|~|",$template);
$t=explode("|~|",$template);
$temp="";
$i=0;
foreach ($t as $n=>$v){
$i++;
if (($i==count($t)||($i==(count($t)-1)&&$t[$n+1]==""))&&substr($v,0,1)=="`"&&substr($v,-1)=="`"){
//Last Item
$temp.="(?P<".substr($v,1,-1).">.++)";
}elseif(substr($v,0,1)=="`"&&substr($v,-1)=="`"){
//Search Item
$temp.="(?P<".substr($v,1,-1).">[^".$t[$n+1]."]++)";
}else{
$temp.=$v;
}
}
$temp="~^".$temp."$~";
preg_match($temp, $string, $matches);
return $matches;
}
This example
print_r(genaric_match("{{name}}:{{city}}-{{state}}","Tom:Some CityPlace-CA"));
Returns
Array
(
[0] => Tom:Some CityPlace-CA
[name] => Tom
[1] => Tom
[city] => Some CityPlace
[2] => Some CityPlace
[state] => CA
[3] => CA
)

Yes, it's called preg_match. But you obviously need to write a regex for it. (If your question is, whether there is a magic recognize-any-pattern-without-even-knowing-it's-syntax function, then the answer is: No.)
preg_match('~^(?P<name>[^:]++):(?P<city>[^-]++)-(?P<state>.++)$~', $string, $matches);
var_dump($matches);

There's no such function in PHP "out of the box", but it would be fairly trivial to write one, as there are quite a few functions such as...
explode
preg_replace
parse_string
etc.
...that you could use to create one.
However, it has to be said that using PHP (which is to a large extent a template language) to create another template language seems an odd choice.

Related

PHP - Remove items from an array with given parameter

I've searched around and I found some similar questions asked, but none that really help me (as my PHP abilities aren't quite enough to figure it out). I'm thinking that my question will be simple enough to answer, as the similar questions I found were solved with one or two lines of code. So, here goes!
I have a bit of code that searches the contents of a given directory, and provides the files in an array. This specific directory only has .JPG image files named like this:
Shot01.jpg
Shot01_tn.jpg
so on and so forth. My array gives me the file names in a way where I can use the results directly in an tag to be displayed on a site I'm building. However, I'm having a little trouble as I want to limit my array to not return items if they contain "_tn", so I can use the thumbnail that links to the full size image. I had thought about just not having thumbnails and resizing the images to make the PHP easier for me to do, but that feels like giving up to me. So, does anyone know how I can do this? Here's the code that I have currently:
$path = 'featured/';
$newest = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS));
$array = iterator_to_array($newest);
foreach($array as $fileObject):
$filelist = str_replace("_tn", "", $fileObject->getPathname());
echo $filelist . "<br>";
endforeach;
I attempted to use a str_replace(), but I now realize that I was completely wrong. This returns my array like this:
Array
(
[0] => featured/Shot01.jpg
[1] => featured/Shot01.jpg
[2] => featured/Shot02.jpg
[3] => featured/Shot02.jpg
[4] => featured/Shot03.jpg
[5] => featured/Shot03.jpg
)
I only have 3 images (with thumbnails) currently, but I will have more, so I'm also going to want to limit the results from the array to be a random 3 results. But, if that's too much to ask, I can figure that part out on my own I believe.
So there's no confusion, I want to completely remove the items from the array if they contain "_tn", so my array would look something like this:
Array
(
[0] => featured/Shot01.jpg
[2] => featured/Shot02.jpg
[4] => featured/Shot03.jpg
)
Thanks to anyone who can help!
<?php
function filtertn($var)
{
return(!strpos($var,'_tn'));
}
$array = Array(
[0] => featured/Shot01.jpg
[1] => featured/Shot01_tn.jpg
[2] => featured/Shot02.jpg
[3] => featured/Shot02_tn.jpg
[4] => featured/Shot03.jpg
[5] => featured/Shot03_tn.jpg
);
$filesarray=array_filter($array, "filtertn");
print_r($filesarray);
?>
Just use stripos() function to check if filename contains _tn string. If not, add to array.
Use this
<?php
$array = Array(
[0] => featured/Shot01.jpg
[1] => featured/Shot01_tn.jpg
[2] => featured/Shot02.jpg
[3] => featured/Shot02_tn.jpg
[4] => featured/Shot03.jpg
[5] => featured/Shot03_tn.jpg
)
foreach($array as $k=>$filename):
if(strpos($filename,"_tn")){
unset($array[$k]);
}
endforeach;
Prnt_r($array);
//OutPut will be you new array removed all name related _tn files
$array = Array(
[0] => featured/Shot01.jpg
[2] => featured/Shot02.jpg
[4] => featured/Shot03.jpg
)
?>
I can't understand what is the problem? Is it required to add "_tn" to array? Just check "_tn" existence and don't add this element to result array.
Try strpos() to know if filename contains string "_tn" or not.. if not then add filename to array
$path = 'featured/';
$newest = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS));
$array = iterator_to_array($newest);
$filesarray = array();
foreach($array as $fileObject):
// Check - string contains "_tn" substring or not
if(!strpos($fileObject->getPathname(), "_tn")){
// Check - value already exists in array or not
if(!in_array($fileObject->getPathname(), $filesarray)){
$filesarray[] = $fileObject->getPathname();
}
}
endforeach;
print_r($filesarray);

Simple regex for comma

Hello can someone help me with this regex please
here is my $lang_file:
define(words_picture,"Снимка");
define(words_amount,"бр.");
define(words_name,"Име");
define(words_price_piece,"Ед. цена");
define(words_total,"Обща цена");
define(words_del,"Изтрий");
define(words_delivery,"Доставка,но няма");
this is my code :
$fh = fopen($lang_file, 'r');
$data = str_replace($rep,"",fread($fh, filesize($lang_file)));
fclose($fh);
preg_match_all('/define\((.*?)\)/i', $data,$defines,PREG_PATTERN_ORDER);
when i print $defines i get this :
[0] => words_picture,"Снимка"
[1] => words_amount,"бр."
[2] => words_name,"Име"
[3] => words_price_piece,"Ед. цена"
[4] => words_total,"Обща цена"
[5] => words_del,"Изтрий"
[6] => words_delivery,"Доставка" //here is the part that is missing and i need it :-)
so when there is a comma inside the string it breaks the string there, and doesn't return correct value.
Try (koko.*?) as the match. That'll return koko for koko,goko. If you want it to return koko,goko, remove the ?. Make it (koko.*). That will return koko,goko for koko,goko.
Here's a site that I use to test my regex against a number of cases:
http://www.cyber-reality.com/regexy.html
based on your edit I'd say you're looking for (koko.*). If your code worked for everything else, use this:
preg_match_all('\(/define.*)\)/i', $data,$defines,PREG_PATTERN_ORDER);

How to replace html tag with other tags using preg-match?

I have a string like the following.
<label>value1<label>:value<br>
<label>value2<label>:value<br>
<label>value3<label>:value<br>
and i need to arrange this as following
<li><label>value1<label><span>value</span><li>
i have tried for this last 2 days, but no luck.Any help?
This really isn't something you should do with regex. You might be able to fudge together a solution that works provided it makes a lot of assumptions about the content it's parsing, but it will always be fragile and liable to break should that content deviate from the expected by any significant degree.
A better bet is using PHP's DOM family of classes. I'm not really at liberty to write the code for you (and that's not what SO is for anyway), but I can give you a pointer regarding the steps you need to follow.
Locate text nodes that follow a label and precede a BR (XPath may be useful here)
Put the text node into a span.
Insert the span into the DOM after the label
Remove the BR.
wrap label and span in an li
If, for the sake of regex, you should use it then follow as below :
$string = <<<TOK
<label>value1<label>:value<br>
<label>value2<label>:value<br>
<label>value3<label>:value<br>
TOK;
preg_match_all('/<label>(.*?)<label>\:(.*?)<br>/s', $string, $matches);
print_r($matches);
/*
Array
(
[0] => Array
(
[0] => value1:value
[1] => value2:value
[2] => value3:value
)
[1] => Array
(
[0] => value1
[1] => value2
[2] => value3
)
[2] => Array
(
[0] => value
[1] => value
[2] => value
)
)
*/
$content = "";
foreach($matches as $key => $match)
{
$content.= "<li><label>{$matches[1][$key]}<label><span>{$matches[2][$key]}</span><li>\n";
}
echo($content);
/*
Output:
<li><label>value1<label><span>value</span><li>
<li><label>value2<label><span>value</span><li>
<li><label>value3<label><span>value</span><li>
*/

Why is a called 'string' invisible to an array?

The file below, can be setup using any JPG file from PhotoShop that has XMP data. In the 'pattern', replace 'eat:' with 'dc:' or any namespace returned from the '$string'.
Calling $string (1) using following array setup it produces a print_r array that looks like: (2)
If you uncomment the line ubove (1a), it will print to the browse, copy & paste into the line below (1a). this should produce an array that looks like: (3)
Why the difference print_r readings, when it's the same string?
How do I get it to behave like (3); ... better yet how do I make it end up like the(4)?
<?php
header("Content-Type: text/html; charset=utf-8");
$filename = "2012-04-24_WestCoast_2.jpg";
echo '<img src="'. $filename . '" alt="'. $filename . '" title="' . $filename . '" width="350" /><p />';
$source = file_get_contents($filename);
$xmpdata_start = strpos($source,'<x:xmpmeta');
$xmpdata_end = strpos($source,"</rdf:Description>");
$xmplenght = $xmpdata_end-$xmpdata_start;
$xmpdata = substr($source,$xmpdata_start,$xmplenght+18);
$string = htmlentities($xmpdata); //(1)
//if (is_string($string)) {
// echo "is a string\n"; //TRUE
//} else {
// echo "is not a string\n";
//}
//$string = print_r("'".$string."';");
// (1a)=====================================
//$string = '<x:xmpmeta xmlns: === Truncated for simplicity ===x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.3-c011 66.145661, 2012/02/06-14:56:27 "> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"></rdf:Description>';
$pattern = '/eat:(.*?)="(.*?)"/is';
preg_match_all($pattern, $string, $matches);
$group = array($matches[1], $matches[2]);
// foreach($group as &$match);
echo '<pre>';
// print_r ($match);
print_r ($group);
echo '</pre>';
?>
(2)=====================================
// If i just call the '$string', this is what i get:
Array
(
[0] => Array
(
)
[1] => Array
(
)
)
(3)=====================================
// If I uncomment (1), the '$string' that I pasted inside the file, i get this:
Array
(
[0] => Array
(
[0] => Biography
[1] => Title
[2] => object_description
[3] => Medium
[4] => in_height
[5] => in_width
[6] => in_depth
[7] => Dated
[8] => Photograph
)
[1] => Array
(
[0] => American B1942 Castine, Maine
[1] => Reunion Dinner Party at the Slanted Door
[2] => Nancy Freeman, Tim Patterson The Slanted Door San Francisco Calf.
[3] => photography
[4] => 2736
[5] => 3648
[6] => # 240 dpi
[7] => April 24, 2012
[8] => PrimaryImage
)
)
(4)=====================================
// This is what i'm trying to get too:
Biography: American B1942 Castine, Maine
Title: Reunion Dinner Party at the Slanted Door
object_description: Reunion Dinner Party at the Slanted Door
Nancy Freeman, Tim Patterson The Slanted Door San Francisco Calf.
Medium: photography
in_height: 2736
in_width: 3648
in_depth: # 240 dpi
Dated: April 24, 2012
Photograph: PrimaryImage
I'm not clear on what the issue is with the string being set inside or outside of file. It is unclear what you are trying to explain.
The output of the array(3) is caused by the brackets in the Regular Expression. I don't know the exact reason for this, but to get the results you want(4) you could use a loop to join the two arrays in a new array.
Note: What your doing with $group is making an array of arrays. You are not merging the two arrays into one. To merge the arrays you need to iterate through both arrays and merging each element as new element of new array.
example:
for($i=0; $i<match[0].length; $i++){
$result[i] = $match[0][i]. ": " .$match[1][i];
}
Im rusty on my php, but that is the idea for merging the arrays.
--EDIT--
Now that I understand what you are trying to do I see two possible places where problems may occur. First is: are you 100% sure the image you are using contains any meta data in the fields you want? Im not sure of the exact nature of meta data, but I do know there will be the required data set by the computer(what you filtered out with the start and end points), and the custom data. If blank it might not even be included.
Second possible issue is how you are chunking up the meta data. Maybe try writing to Regular Expressions to strip the start and end from the string. Replace everything in front of a set of characters with "" and do a similar expression for the back.
Also the variable you set for $group is the exact same thing that $match was. You took the two arrays that where contained in the array %match and assigned them to an array called $group. Just a FYI. Use the sudo code I posted earlier to design the loop that will actually combine the two arrays into one.
Good Luck. Maybe when I get php set up on testing computer I will play with the code to see what exactly is happening.
Well it looks like i get to answer my own question of "Why it is a called 'string' invisible to an array?".
The answer is: When it's preceded by a call to 'htmlentities()'.
Now I'm not really sure why it happens but it does happen and the instant I went back and checked all my assumptions ... that 'htmlentities()' would clean up the raw string. Commenting out 'htmlentities()' made everything work.
Is this a bug? I personally don't know, and i don't have the necessary experience using PHP to even hazard a guess. What i do know is it drove me up the wall for a week.

I'm trying to parse some text in html with custom nested tags

I would like to parse some text into an array:
My text looks like this:
You've come to the {right; correct; appropriate} place! Start by {searching; probing; inquiring} our site below, or {browse; {search; lookup; examine}} our list of popular support articles.
The third group of words has nested tags. How can I ignore the opening and closing nested tags to achieve an array such as
$tags[0][0] = 'right';
$tags[0][1] = 'suitable';
$tags[0][2] = 'appropriate';
$tags[1][0] = 'searching';
$tags[1][1] = 'probing';
$tags[1][2] = 'inquiring';
$tags[2][1] = 'browse';
$tags[2][2] = 'search';
$tags[2][3] = 'lookup';
$tags[2][4] = 'examine';
Essentially ignoring the nesting of the tags.
Any help would be greatly appreciated.
My only current ideas for this is to traverse the text character by character until I find a { which would increment a "depth" variable. Capture the words in between until I find a } decreasing the depth variable and upon it returning to zero, stop capturing words. I was just wondering if there's a much easier way of doing this. Thanks.
Thanks for your excellent help, I modified it a bit to come up with the following solution.
$code = "You've come to {the right; the correct; the appropriate} place!
Start by {searching; probing; inquiring} our site below, or
{browse; {search; {foo; bar}; lookup}; examine} our list of
popular support articles.";
echo $code."\r\n\r\n";
preg_match_all('/{((?:[^{}]*|(?R))*)}/', $code, $matches);
$arr = array();
$r = array('{','}');
foreach($matches[1] as $k1 => $m)
{
$ths = explode(';',str_replace($r,'',$m));
foreach($ths as $key => $val)
{
if($val!='')
$arr[$k1][$key] = trim($val);
$code = str_replace($matches[0][$k1],'[[rep'.$k1.']]',$code);
}
}
echo $code;
Returns
You've come to {the right; the correct; the appropriate} place! Start by {searching; probing; inquiring} our site below, or {browse; {search; {foo; bar}; lookup}; examine} our list of popular support articles.
You've come to [[rep0]] place! Start by [[rep1]] our site below, or [[rep2]] our list of popular support articles.
My only current ideas for this is to traverse the text character by character until I find a { which would increment a "depth" variable. Capture the words in between until I find a } decreasing the depth variable and upon it returning to zero, stop capturing words. I was just wondering if there's a much easier way of doing this.
That sounds like a reasonable way to do it. Another way to do this is by using a bit of regex, although that might result in a solution that is (far) less readable (and therefor less maintainable) than your own solution.
<?php
$text = "You've come to the {right; correct; appropriate} place!
Start by {searching; probing; inquiring} our site below, or
{browse; {search; {foo; bar}; lookup}; examine} our list of
popular support articles. {the right; the correct; the appropriate}";
preg_match_all('/{((?:[^{}]*|(?R))*)}/', $text, $matches);
$arr = array();
foreach($matches[1] as $m) {
preg_match_all('/\w([\w\s]*\w)?/', $m, $words);
$arr[] = $words[0];
}
print_r($arr);
?>
would produce:
Array
(
[0] => Array
(
[0] => right
[1] => correct
[2] => appropriate
)
[1] => Array
(
[0] => searching
[1] => probing
[2] => inquiring
)
[2] => Array
(
[0] => browse
[1] => search
[2] => foo
[3] => bar
[4] => lookup
[5] => examine
)
[3] => Array
(
[0] => the right
[1] => the correct
[2] => the appropriate
)
)

Categories