I'm trying to template a document, I want to replace section of the document with dynamic text by searching a document for [%text%] and replacing it with $array['text'] or $text. I know I can use str_replace("[%text%]", $array['text'], $page), but I want to find all instances of [%(.*?)%] and replace with with $array[$1] instead of $1. I've tried using create_function($matches, $array), but it complains about Missing argument 2 for {closure}().
$page = preg_replace('#\[%(.*?)%\]#is', $array["$1"], $page);
You can preg_match_all('#[%(.*?)%]#is', $page, $matches); and then
if(count($matches == 2))
{
$key = 0;
foreach(array_unique($matches[0]) as $val)
{
if(isset($array[$key]))
{
$page = str_replace($val, $array[$key++], $page);
}
else
{
break; // more matches than array elements
}
}
}
First do a preg_match and find the matching names. Then craete the array with replacements for every found name. Then use preg_replace with the array as second argument, thereby replacing the names with the items from the array.
You can do it with preg_replace_callback.
<?php
$page = preg_replace_callback('#\[%(.*?)%\]#is',
function ($m){
GLOBAL $array;
return $array[$m[1]];
}
, $page);
?>
Related
I have a comma separated list of prefixes stored in a variable
$prefixes = “fa,go,urg”;
and a word stored in another variable
$word = “good”;
Now I want to know efficient way to check if any of the prefixes stored in $prefixes is the prefix of $word or not.
My intention is
If any of the prefixes stored in $prefixes is the prefix of the word stored in $word return TRUE.
If none of the prefixes stored in $prefixes is the prefix of the word stored in $word return FALSE.
Note:- Comma separated list of prefixes is provide by user using text box.
One thing that can be done is to have the prefixes within an array, and then check if $word is present within the array $preArr using in_array
in_array
(PHP 4, PHP 5, PHP 7)
in_array — Checks if a value exists in an array
$prefixes = “fa,go,urg”;
$preArr = explode(',', $prefixes); // Convert to array
$word = “good”;
if (in_array($word, $preArr)) {
echo "Success!";
} else {
echo "Failure!";
}
The substr function can achieve the desired result. It checks for the word good in the prefixes at specified location, which is the beginning of the word.
From the PHP Manual:
substr — Return part of a string
Description
string substr ( string $string , int $start [, int $length ] )
Returns the portion of string specified by the start and length parameters.
Try this:
$prefixes = “fa,go,urg”;
$word = “good”;
$Arr[] = explode(',', $prefixes); // Convert to array
$elements = count($Arr[]); //get total elements in array
for ($i=0;$i<count;$i++) {
if (substr( $Arr(i), 0, 4 ) === $word) {
return true;
}
else {return false;}
}
Your problem can be solved by a few ways, the most programmatic method being to just do a simple check, iterate across $prefixes and check it against 0.....i where i = N - 1 and N = count($prefixes[$i])
function inPrefixArr($prefixes, $word) {
$prefixesInArray = explode(',', $prefixes);
for ($i = 0; $i < count($prefixesInArray); i++) {
if (count($prefixesInArray[$i]) <= count($word)) {
if ($prefixesInArray[$i] == substr($word, 0, count($prefixesInArray[$i]))) {
return True;
}
}
}
return False
}
This checks if the any of the prefixes are a prefix of the word given in O(mn) time where m is the max length of some prefix in the array given. It is also the fastest and most space optimal solution that can be found.
As it seems you weren't asking for a theoretical/CS question, there are other interesting ways to implement this in other data structures which can yield better runtimes if you do this repeatedly.
I have this code in php -:
function pregRepler($matches)
{
* do something
}
$str = preg_replace_callback($reg_exp,'pregRepler',$str);
When in function pregRepler, i would want to know the current match number like if it is the first match or the second or anything...
How do i do it.??
Try something like this:
function pregRepler($matches) {
static $matchcount = 0;
// do stuff
$matchcount++;
}
This works better with an anonymous function, as I mentioned in my answer to your other question, as this will avoid problems if you have multiple calls to preg_replace_callback.
You need to share a $count variable between both variable scopes, for example by using a variable alias:
$callback = function($matches) use (&$count) {
$count++;
return sprintf("<%d:%s>", $count, $matches[0]);
};
echo preg_replace_callback($pattern, $callback , $subject, $limit = -1, $count);
Before invoking, $count is equal to 0. After invoking $count is set to the number of replacements done. In between you can count up in your callback. You can also set to zero again when calling another time.
See it in action
See http://php.net/preg_replace_callback
$repled = 0;
function pregRepler($matches)
{
* do something
global $repled;
$repled++;
}
$str = preg_replace_callback($reg_exp,'pregRepler',$str);
Just count from a global variable.
I'm wondering if it is possible to truncate an array by using a regular expression.
In particular I have an array like this one:
$array = array("AaBa","AaBb","AaBc","AaCa","AaCb","AaCc","AaDa"...);
I have this string:
$str = "AC";
I'd like the slice of $array from the start to the last occurrence of a string matching /A.C./ (in the sample, "AaCc" at index 5):
$result = array("AaBa","AaBb","AaBc","AaCa","AaCb","AaCc");
How can I do this? I thought I might use array_slice, but I don't know how to use a RegEx with it.
Here's my bid
function split_by_contents($ary, $pattern){
if (!is_array($ary)) return FALSE; // brief error checking
// keep track of the last position we had a match, and the current
// position we're searching
$last = -1; $c = 0;
// iterate over the array
foreach ($ary as $k => $v){
// check for a pattern match
if (preg_match($pattern, $v)){
// we found a match, record it
$last = $c;
}
// increment place holder
$c++;
}
// if we found a match, return up until the last match
// if we didn't find one, return what was passed in
return $last != -1 ? array_slice($ary, 0, $last + 1) : $ary;
}
Update
My original answer has a $limit argument that served no purpose. I did originally have a different direction I was going to go with the solution, but decided to keep it simple. However, below is the version that implements that $limit. So...
function split_by_contents($ary, $pattern, $limit = 0){
// really simple error checking
if (!is_array($ary)) return FALSE;
// track the location of the last match, the index of the
// element we're on, and how many matches we have found
$last = -1; $c = 0; $matches = 0;
// iterate over all items (use foreach to keep key integrity)
foreach ($ary as $k => $v){
// text for a pattern match
if (preg_match($pattern, $v)){
// record the last position of a match
$last = $c;
// if there is a specified limit, capture up until
// $limit number of matches, then exit the loop
// and return what we have
if ($limit > 0 && ++$matches == $limit){
break;
}
}
// increment position counter
$c++;
}
I think the easiest way might be with a foreach loop, then using a regex against each value - happy to be proven wrong though!
One alternative could be to implode the array first...
$array = array("AaBa","AaBb","AaBc","AaCa","AaCb","AaCc","AaDa"...);
$string = implode('~~',$array);
//Some regex to split the string up as you want, guessing something like
// '!~~A.C.~~!' will match just what you want?
$result = explode('~~',$string);
If you'd like a hand with the regex I can do, just not 100% on exactly what you're asking - the "A*C*"-->"AaCc" bit I'm not too sure on?
Assuming incremental numeric indices starting from 0
$array = array("AaBa","AaBb","AaBc","AaCa","AaCb","AaCc","AaDa");
$str = "AC";
$regexpSearch = '/^'.implode('.',str_split($str)).'.$/';
$slicedArray = array_slice($array,
0,
array_pop(array_keys(array_filter($array,
function($entry) use ($regexpSearch) {
return preg_match($regexpSearch,$entry);
}
)
)
)+1
);
var_dump($slicedArray);
PHP >= 5.3.0 and will give a
Strict standards: Only variables should be passed by reference
And if no match is found, will still return the first element.
I've created a .info file similar to how you would in drupal.
#Comment
Template Name = Valley
styles[] = styles/styles.css, styles/media.css
scripts[] = js/script.js
I want to use PHP get each variable and their values. For example I'd like to put the Template Name value to a PHP variable called Template Name and put the styles[] values in an array if there is mroe than one.
I'd also need to avoid it picking up on comments that are defined be a hash # before the text.
It seems a lot to ask, bt I'm really not sure how to go about doing this. If someone has a solution I'd be very greatful, however if someone could just point me in the right direction that'll be just as helpful.
Thanks in advanced!
If you can adkust your info file slightly, you can use a built-in PHP function:
http://php.net/manual/en/function.parse-ini-file.php
#Comment
TemplateName = Valley
styles[] = "styles/styles.css"
styles[] = "styles/media.css"
scripts[] = "js/script.js"
which will result in an array
If all you're after is something "similar" you could take a look at the parse_ini_file() function.
Drupal was a good hint:
function drupal_parse_info_file($filename) {
$info = array();
$constants = get_defined_constants();
if (!file_exists($filename)) {
return $info;
}
$data = file_get_contents($filename);
if (preg_match_all('
#^\s* # Start at the beginning of a line, ignoring leading whitespace
((?:
[^=;\[\]]| # Key names cannot contain equal signs, semi-colons or square brackets,
\[[^\[\]]*\] # unless they are balanced and not nested
)+?)
\s*=\s* # Key/value pairs are separated by equal signs (ignoring white-space)
(?:
("(?:[^"]|(?<=\\\\)")*")| # Double-quoted string, which may contain slash-escaped quotes/slashes
(\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
([^\r\n]*?) # Non-quoted string
)\s*$ # Stop at the next end of a line, ignoring trailing whitespace
#msx', $data, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
// Fetch the key and value string
$i = 0;
foreach (array('key', 'value1', 'value2', 'value3') as $var) {
$$var = isset($match[++$i]) ? $match[$i] : '';
}
$value = stripslashes(substr($value1, 1, -1)) . stripslashes(substr($value2, 1, -1)) . $value3;
// Parse array syntax
$keys = preg_split('/\]?\[/', rtrim($key, ']'));
$last = array_pop($keys);
$parent = &$info;
// Create nested arrays
foreach ($keys as $key) {
if ($key == '') {
$key = count($parent);
}
if (!isset($parent[$key]) || !is_array($parent[$key])) {
$parent[$key] = array();
}
$parent = &$parent[$key];
}
// Handle PHP constants.
if (isset($constants[$value])) {
$value = $constants[$value];
}
// Insert actual value
if ($last == '') {
$last = count($parent);
}
$parent[$last] = $value;
}
}
return $info;
}
Source, this function is part of the drupal code-base, drupal's license applies, used for documentation purposes here only.
I have an array of tags that I'm pulling from a database, I am exporting the tags out into a tag cloud. I'm stuck on getting only the first instance of the word. For example:
$string = "test,test,tag,tag2,tag3";
$getTags = explode("," , $string);
foreach ($getTags as $tag ){
echo($tag);
}
This would output the test tag twice. at first i thought i could use stristr to do something like:
foreach ($getTags as $tag ){
$tag= stristr($tag , $tag);
echo($tag);
}
This is obviously silly logic and doesn't work, stristr seems to only replace the first occurrence so something like "test 123" would only get rid of the "test" and would return "123" I've seen this can also be done with regex but I haven't found a dynamic exmaple of that.
Thanks,
Brooke
Edit: unique_array() works if I'm using a static string but won't work with the data from the database because I'm using a while loop to get each rows data.
$getTag_data = mysql_query("SELECT tags FROM `news_data`");
if ($getTag_data)
{
while ($rowTags = mysql_fetch_assoc($getTag_data))
{
$getTags = array_unique(explode("," , $rowTags['tags']));
foreach ($getTags as $tag ){
echo ($tag);
}
}
}
use array_unique()
$string = "test,test,tag,tag2,tag3";
$getTags = array_unique(explode("," , $string));
foreach ($getTags as $tag ){
echo($tag);
}
Use your words as keys to the dictionary, not as values.
$allWords=array()
foreach(explode("," , $string) as $word)
$allWords[$word]=true;
//now you can extract these keys to a regular array if you want to
$allWords=array_keys($allWords);
While you are at it, you can also count them!
$wordCounters=array()
foreach(explode("," , $string) as $word)
{
if (array_key_exists($word,$wordCounters))
$wordCounters[$word]++;
else
$wordCounters=1;
}
//word list:
$wordList=array_keys($wordCounters);
//counter for some word:
echo $wordCounters['test'];
I'm assuming that each row in your table contains more than one tag, separated by coma, like this:
Row0: php, regex, stackoverflow
Row1: php, variables, scope
Row2: c#, regex
If that's the case, try this:
$getTag_data = mysql_query("SELECT tags FROM `news_data`");
//fetch all the tags you found and place it into an array (with duplicated entries)
$getTags = array();
if ($getTag_data) {
while ($row = mysql_fetch_assoc($getTag_data)) {
array_merge($getTags, explode("," , $row['tags']);
}
}
//clean up duplicity
$getTags = array_unique($getTags);
//display
foreach ($getTags as $tag ) {
echo ($tag);
}
I'd point out that this is not efficient.
Another option (already mentioned here) would be to use the tags as array keys, with the advantage of being able to count them easily.
You could do it like this:
$getTag_data = mysql_query("SELECT tags FROM `news_data`");
$getTags = array();
if ($getTag_data) {
while ($row = mysql_fetch_assoc($getTag_data)) {
$tags = explode("," , $row['tags']);
foreach($tags as $t) {
$getTags[$t] = isset($getTags[$t]) ? $getTags[$t]+1 : 1;
}
}
}
//display
foreach ($getTags as $tag => $count) {
echo "$tag ($count times)";
}
please keep in mind none of this code was tested, it's just so you get the idea.
I believe php's array_unique is what you are looking for:
http://php.net/manual/en/function.array-unique.php
Use the array_unique function before iterating over the array? It removes every duplicate string and return the unique functions.