php - str_replace 2 parts with 2 different results - php

I want to add some html to a word based on the words in a compound word.
For instance let's take the word "doghouse'
Let's say
$row2['word'] = 'doghouse';
$word = 'dog';
$otherword = 'house';
I want the end result to produce
<span style="color:blue">dog</span><span style="color:red">house</span>
My code so far that does not work (which I thought I could array the replace in str_replace but apparently I can't.
$finalword = str_replace(array($word,$otherword),array("<span style='color:blue'>".$word."</span>","<span style='color:red'>".$word."</span>"),$row2['word']);
Is str_replace the wrong choice for this?

str_replace is the correct function, but you're not really using it correctly. The way you've set it up, $row2 would have to be an array, but it's not, it's a string. So you need to use an alternate approach. Your code should look like this:
str_replace($row2, $word.$otherword, "<span style='color:blue'>".$word."</span><span style='color:red'>".$otherword."</span>");
The first term ($row2) is where you're searching, what php calls the 'haystack'. The second term $word.$otherword is what you're searching for (the 'needle'). The third term is what you replace the 'needle' with when you find it.

I don't know how do you store your colors, but does it work for you?
$row2['word'] = 'doghouse';
$words = array('dog','house');
$colors = array('blue', 'red');
$finalword = "";
for ($i = 0; $i < count($words); $i++) {
$finalword .= "<span style='color:".$colors[$i]."'>".$words[$i]."</span>";
}
echo $finalword;

Related

Extracting meaningful data from this complicated string in PHP

I'm receiving some structured data for my PHP application, but the format is somewhat unpredictable and difficult to deal with. I don't get a say in the initial format of the data. What I get is a string (sample given below).
[9484,'Víctor Valdés',8,[[['accurate_pass',[15]],['touches',[42]],['saves',[4]],['total_pass',[24]],['good_high_claim',[2]],['formation_place',[1]]]],1,'GK',1,0,0,'GK',31,183,78],[1320,'Carles Puyol',7.76,[[['accurate_pass',[50]],['touches',[75]],['aerial_won',[3]],['total_pass',[55]],['total_tackle',[1]],['formation_place',[6]]]],2,'DC',5,0,0,'D(CLR)',35,178,80],[5780,'Dani Alves',8.21,[[['accurate_pass',[58]],['touches',[99]],['total_scoring_att',[1]],['total_pass',[66]],['total_tackle',[6]],['aerial_lost',[1]],['fouls',[4]],['formation_place',[2]]]],2,'DR',22,0,0,'D(CR)',30,173,64],[83686,'Marc Bartra',8.31,[[['accurate_pass',[64]],['touches',[88]],['won_contest',[1]],['total_scoring_att',[1]],['aerial_won',[1]],['total_pass',[66]],['total_tackle',[5]],['aerial_lost',[1]],['fouls',[1]],['formation_place',[5]]]],2,'DC',15,0,0,'D(C)',22,181,70],[13471,'Adriano',6.72,[[['accurate_pass',[16]],['touches',[28]],['aerial_won',[2]],['total_pass',[18]],['total_tackle',[1]],['formation_place',[3]]]],2,'DL',21,1,31,'D(CLR),M(LR)',29,172,67]
The above is data for 5 football players. This is what I need to get:
[9484,'Víctor Valdés',8,[[['accurate_pass',[15]],['touches',[42]],['saves',[4]],['total_pass',[24]],['good_high_claim',[2]],['formation_place',[1]]]],1,'GK',1,0,0,'GK',31,183,78]
[1320,'Carles Puyol',7.76,[[['accurate_pass',[50]],['touches',[75]],['aerial_won',[3]],['total_pass',[55]],['total_tackle',[1]],['formation_place',[6]]]],2,'DC',5,0,0,'D(CLR)',35,178,80]
[5780,'Dani Alves',8.21,[[['accurate_pass',[58]],['touches',[99]],['total_scoring_att',[1]],['total_pass',[66]],['total_tackle',[6]],['aerial_lost',[1]],['fouls',[4]],['formation_place',[2]]]],2,'DR',22,0,0,'D(CR)',30,173,64]
[83686,'Marc Bartra',8.31,[[['accurate_pass',[64]],['touches',[88]],['won_contest',[1]],['total_scoring_att',[1]],['aerial_won',[1]],['total_pass',[66]],['total_tackle',[5]],['aerial_lost',[1]],['fouls',[1]],['formation_place',[5]]]],2,'DC',15,0,0,'D(C)',22,181,70]
[13471,'Adriano',6.72,[[['accurate_pass',[16]],['touches',[28]],['aerial_won',[2]],['total_pass',[18]],['total_tackle',[1]],['formation_place',[3]]]],2,'DL',21,1,31,'D(CLR),M(LR)',29,172,67]
Now, what I've done manually in the above example I need to do reliably with PHP. As you see, each player has a set of data. In order to split the big string into individual players, I can't just explode it by "],[" because that substring appears within each player's data too an unpredictable number of times.
Each player has a certain number of statistics (accurate_pass, touches etc) but they don't all have the same statistics. For instance, player #1 has "saves" and the others don't. Player #4 has "won_contest" and the others don't. There is no way to know who will have which stats. That means I can't just count commas until the new player or something similar.
Each player has a number before his name, but that number has an unpredictable number of digits and there's no way to discern it from other numbers which may appear in the string.
What I see as a constant occurrence for all players is the last bit: before the last closed bracket there are always 3 integers divided by commas. This type of substring (INT,INT,INT]) doesn't seem to appear in any other situation. Maybe this could be of some use?
A "hard" way to do this is parenthesis counting (less common in PHP, more common in text parsing languages)...
<?php
$str = "[9484,'Víctor Valdés',8,[[['accurate_pass',[15]],['touches',[42]],['saves',[4]],['total_pass',[24]],['good_high_claim',[2]],['formation_place',[1]]]],1,'GK',1,0,0,'GK',31,183,78],[1320,'Carles Puyol',7.76,[[['accurate_pass',[50]],['touches',[75]],['aerial_won',[3]],['total_pass',[55]],['total_tackle',[1]],['formation_place',[6]]]],2,'DC',5,0,0,'D(CLR)',35,178,80],[5780,'Dani Alves',8.21,[[['accurate_pass',[58]],['touches',[99]],['total_scoring_att',[1]],['total_pass',[66]],['total_tackle',[6]],['aerial_lost',[1]],['fouls',[4]],['formation_place',[2]]]],2,'DR',22,0,0,'D(CR)',30,173,64],[83686,'Marc Bartra',8.31,[[['accurate_pass',[64]],['touches',[88]],['won_contest',[1]],['total_scoring_att',[1]],['aerial_won',[1]],['total_pass',[66]],['total_tackle',[5]],['aerial_lost',[1]],['fouls',[1]],['formation_place',[5]]]],2,'DC',15,0,0,'D(C)',22,181,70],[13471,'Adriano',6.72,[[['accurate_pass',[16]],['touches',[28]],['aerial_won',[2]],['total_pass',[18]],['total_tackle',[1]],['formation_place',[3]]]],2,'DL',21,1,31,'D(CLR),M(LR)',29,172,67]";
$line = ',';
$paren_count = 0;
$lines = array();
for($i=0; $i<strlen($str); $i++)
{
$line.= $str{$i};
if($str{$i} == '[') $paren_count++;
elseif($str{$i} == ']')
{
$paren_count--;
if($paren_count == 0)
{
$lines[] = substr($line,1);
$line = '';
}
}
}
print_r($lines);
?>
Looks like #Boundless answer is correct, you can use json_decode, but you need to do a couple of things to the string you get first, which also seems like a valid json formatted string.
This worked for me:
<?php
$str = "[9484,'Víctor Valdés',8,[[['accurate_pass',[15]],['touches',[42]],['saves',[4]],['total_pass',[24]],['good_high_claim',[2]],['formation_place',[1]]]],1,'GK',1,0,0,'GK',31,183,78],[1320,'Carles Puyol',7.76,[[['accurate_pass',[50]],['touches',[75]],['aerial_won',[3]],['total_pass',[55]],['total_tackle',[1]],['formation_place',[6]]]],2,'DC',5,0,0,'D(CLR)',35,178,80],[5780,'Dani Alves',8.21,[[['accurate_pass',[58]],['touches',[99]],['total_scoring_att',[1]],['total_pass',[66]],['total_tackle',[6]],['aerial_lost',[1]],['fouls',[4]],['formation_place',[2]]]],2,'DR',22,0,0,'D(CR)',30,173,64],[83686,'Marc Bartra',8.31,[[['accurate_pass',[64]],['touches',[88]],['won_contest',[1]],['total_scoring_att',[1]],['aerial_won',[1]],['total_pass',[66]],['total_tackle',[5]],['aerial_lost',[1]],['fouls',[1]],['formation_place',[5]]]],2,'DC',15,0,0,'D(C)',22,181,70],[13471,'Adriano',6.72,[[['accurate_pass',[16]],['touches',[28]],['aerial_won',[2]],['total_pass',[18]],['total_tackle',[1]],['formation_place',[3]]]],2,'DL',21,1,31,'D(CLR),M(LR)',29,172,67]";
$str = '[' . $str . ']';
$str = str_replace('\'','"', $str);
//convert string to array
$arr = json_decode($str);
//now it's a php array so you can access any value
//echo '<pre>';
//print_r( $arr );
//echo '</pre>';
echo $arr [0][1]; //prints "Victor Valdes"
?>
Your string looks like JSON but it is not valid JSON so json_decode() will not work.
Your specific case could be converted to valid JSON by wrapping the string in a pair of [] and replacing the single quotes with double quotes:
$string = str_replace("'", '"', $your_string);
var_dump(json_decode('[' . $string . ']'));
See this example.
Of course the best solution would be to make sure that valid JSON is supplied because this will break easily if your text strings contain for example double quotes.
Try parsing as json, then pulling out what you want. Assuming that the data comes in blocks of 4 you can try:
$arr = json_decode($str);
for($i = 0; $i < count($arr) - 3; $i += 4)
{
$arr[] = new array($arr[$i], $arr[$i + 1], $arr[$i + 2], $arr[$i + 3]);
}
Why not count the [ in a loop? Here's a quick untested loop that could get you started.
$output = array('');
$brackets = 0;
$index = 0;
foreach (str_split($input) as $ch) {
if ($ch == '[') {
$brackets++;
}
$output[$index] .= $ch;
if ($ch == ']') {
$brackets--;
if ($brackets === 0) {
$index++;
$output[$index] = '';
}
}
}
Not very elegant though...

possible limitation of implode function in PHP

I have the following code that is not returning as I expected. I was hoping the final result would be a string:
$organizers = array_unique($organizers); // this returns correctly
$organizers = implode(', ', $organizers); // this returns nothing
var_dump($organizers); // no data appears here
exit;
The array_unique() function is returning data correctly and I can see the array it returns. To start, the $organizers array is a simple 1-D array of strings that all have small lengths under 20 chars. I think the issue might be that $organizers is more than 10,000 indices long. Are there limitations on the length of an array that can be imploded? Are there work-arounds for that? I cannot find anything in the manual, but I have tested this code thoroughly and I believe the error must be on implode().
I dont' know if there is a limitation, but what comes to my mind is taht you are also transforming an array into a string. This shouldn't be the problem in PHP, but try calling it a different variable for the result of implode?
$organizers = array_unique($organizers); // this returns correctly
$organizers_string = implode(', ', $organizers); // this returns nothing
// This gives it a different space
Edit: And if for some reason implode() is still problematic.
$organizers = array_unique($organizers);
$neworganizers = "";
for($i = 0; $i < sizeof($organizers); $i++)
{
$neworganizers .= $organizers[$i];
if($i != sizeof($organizers) - 1)
{
$neworganizers .= ", ";
}
}
//$neworganizers is now the equivalent of what .implode() should return when called on $organizers
$organizers = array();
$organizers[0] = "value1";
$organizers[1] = "value2";
$organizers[2] = "value3";
$organizers[3] = "value3";
$organizers = array_unique($organizers); // strips out last index
$organizers = implode(', ', $organizers); // returns string of "value1, value2, value3"
echo $organizers;
This seemed to work on writecodeline.com/php/
I've also experienced issues with older php builds when I've tried to explode/implode by a string with special characters in it and they were encapsulated by single quotes. I know it sounds crazy, but the double quotes might be necessary on some servers.
Reference: personal experience doing work on older production servers.
I'd hate to think I'm stating the obvious, but doesn't implode only take a string as an argument? Maybe it should be something more like this...
$organizers = array_unique($organizers);
//I'm guessing what you wanted was an array of arrays?
$neworganizers = array();
for($i = 0; $i < sizeof($organizers); $i++)
{
$neworganizers[$i] = implode(", ", $organizers);
}
print_r($neworganizers);

preg_match on dynamic url

Is there a way in php to do a preg_match on a url like below
dynamic/dynamic/dev/new_mobile/lib
and it would only pull out dev/new_mobile, and the link also has the ability to be like this too
dynamic/dynamic/dynamic/tst/new_mobile/lib
In the above example it would only pull out tst/new_mobile. The key is it would grab the last two directories before lib. Any idea how this could be done?
Here's a regex that will get the part you want:
$url = 'dynamic/tst/new_mobile/lib/foo/bar';
if (preg_match('#^(?:.*?/)?([^/]+/[^/]+)/lib(?:/.+)?$#', $url, $matches)) {
$part = $matches[1];
var_dump($part); // "tst/new_mobile"
}
This will get the 2 directories before the lib directory allowing for any directories before and after. It will also match a couple of edge cases that you don't mention whether you need:
tst/new_mobile/lib/foo/bar
/tst/new_mobile/lib/foo/bar
just explode then reverse array, simple and easy to use.
$array_url = explode('/',$url);
$tmp_array_url = array_reverse($array_url);
then you can rebuild as you will, no need to wonder with how many dynamic parts come before.
echo $tmp_array_url[0]; // "lib";
echo $tmp_array_url[1]; // "new_mobile";
echo $tmp_array_url[2]; // "dev";
EDIT: since you got lib constant, just do something like this :
$the_two_before = "";
for($i = 0; $i < count($tmp_array_url); $i++){
if($tmp_array_url[$i] == "lib"){
$the_two_before = $tmp_array_url[$i+2]."/".$tmp_array_url[$i+1];
}
}

Regex for number comparison?

I would like to perform regex to return true/false if the input 5 digit from input matching data in database, no need to cater of the sequence, but need the exact numbers.
Eg: In database I have 12345
When I key in a 5 digit value into search, I want to find out whether it is matching the each number inside the 12345.
If I key in 34152- it should return true
If I key in 14325- it should return true
If I key in 65432- it should return false
If I key in 11234- it should return false
Eg: In database I have 44512
If I key in 21454- it should return true
If I key in 21455- it should return false
How to do this using php with regex
This is a way avoiding regex
<?php
function cmpkey($a,$b){
$aa = str_split($a); sort($aa);
$bb = str_split($b); sort($bb);
return ( implode("",$aa) == implode("",$bb));
}
?>
Well, it's not going to be a trivial regex, I can tell you that. You could do something like this:
$chars = count_chars($input, 1);
$numbers = array();
foreach ($chars as $char => $frequency) {
if (is_numeric(chr($char))) {
$numbers[chr($char)] = $frequency;
}
}
// that converts "11234" into array(1 => 2, 2 => 1, 3 => 1, 4 => 1)
Now, since MySQL doesn't support assertions in regex, you'll need to do this in multiple regexes:
$where = array();
foreach ($numbers AS $num => $count) {
$not = "[^$num]";
$regex = "^";
for ($i = 0; $i < $count; $i++) {
$regex .= "$not*$num";
}
$regex .= "$not*";
$where[] = "numberField REGEXP '$regex'";
}
$where = '((' . implode(') AND (', $where).'))';
That'll produce:
(
(numberField REGEXP '^[^1]*1[^1]*1[^1]*$')
AND
(numberField REGEXP '^[^2]*2[^2]*$')
AND
(numberField REGEXP '^[^3]*3[^3]*$')
AND
(numberField REGEXP '^[^4]*4[^4]*$')
)
That should do it for you.
It's not pretty, but it should take care of all of the possible permutations for you, assuming that your stored data format is consistent...
But, depending on your needs, you should try to pull it out and process it in PHP. In which case the regex would be far simpler:
^(?=.*1.*1})(?=.*2)(?=.*3)(?=.*4)\d{5}$
Or, you could also pre-sort the number before you insert it. So instead of inserting 14231, you'd insert 11234. That way, you always know the sequence is ordered properly, so you just need to do numberField = '11234' instead of that gigantic beast above...
Try using
^(?=.*1)(?=.*2)(?=.*3)(?=.*4)(?=.*5).{5}$
This will get much more complicated, when you have duplicate numbers.
You really should not do this with regex. =)

Filtering out highest integer from an array of links

But of a confusing title so let me explain. I have an array of links like this:
http://somesite.com/videoplayback?ip=81.0.0.0&sparams=id,expire,ip,ipbits,itag,algorithm,burst,factor&fexp=905602&algorithm=throttle-factor&itag=34&ipbits=8&burst=40&sver=3&expire=1285056000&key=yt1&signature=690F9475D5288F3129F84364427B2B490B6ACE59.45C8F83DEE3DD361855B12AE538EA6349FF8EF9B&factor=1.25&id=d50e6528eb51ad54,18
http://somesite.com/videoplayback?ip=81.0.0.0&sparams=id,expire,ip,ipbits,itag,algorithm,burst,factor&fexp=905602&algorithm=throttle-factor&itag=18&ipbits=8&burst=40&sver=3&expire=1285056000&key=yt1&signature=A68EAA3F7A2ECA2BB2BD6C35BF443C03E4BB1172.AD2FF9FDAF046B23F789FE1A7F7882DF9A355DE4&factor=1.25&id=d50e6528eb51ad54,5
http://somesite.com/videoplayback?ip=81.0.0.0&sparams=id,expire,ip,ipbits,itag,algorithm,burst,factor&fexp=905602&algorithm=throttle-factor&itag=5&ipbits=8&burst=40&sver=3&expire=1285056000&key=yt1&signature=ABC8ACF6899C46CC992ECB5F6A6FD7E66383EA3D.0C8B707083203DC1153FB26586A94BFAC64D176B&factor=1.25&id=d50e6528eb51ad54
If you look at the very end of those URL's, they have extensions like ,18, ,5 and there is one last link with no extension like this at all.
Now, I need to use the link that has the highest number on the end as possible later in my code. In this example I need to filter out the very first link, because it has the highest integer on the end (18).
I would use a series of if() blocks, but in this case the integers on the end can change so that's not a good solution.
So I basically need to go through my array, check which link has the highest integer at the end (note that it is only 2 digits in length) and then store it in another variable.
Can anyone provide some sample/psudo code on how to effectively do this?
Cheers.
This will work even if there are commas in other places in the URL:
$links = array("http://somesite.com/videoplayback?ip=81.0.0.0&sparams=id,expire,ip,ipbits,itag,algorithm,burst,factor&fexp=905602&algorithm=throttle-factor&itag=34&ipbits=8&burst=40&sver=3&expire=1285056000&key=yt1&signature=690F9475D5288F3129F84364427B2B490B6ACE59.45C8F83DEE3DD361855B12AE538EA6349FF8EF9B&factor=1.25&id=d50e6528eb51ad54,18", "http://somesite.com/videoplayback?ip=81.0.0.0&sparams=id,expire,ip,ipbits,itag,algorithm,burst,factor&fexp=905602&algorithm=throttle-factor&itag=18&ipbits=8&burst=40&sver=3&expire=1285056000&key=yt1&signature=A68EAA3F7A2ECA2BB2BD6C35BF443C03E4BB1172.AD2FF9FDAF046B23F789FE1A7F7882DF9A355DE4&factor=1.25&id=d50e6528eb51ad54,5", "http://somesite.com/videoplayback?ip=81.0.0.0&sparams=id,expire,ip,ipbits,itag,algorithm,burst,factor&fexp=905602&algorithm=throttle-factor&itag=5&ipbits=8&burst=40&sver=3&expire=1285056000&key=yt1&signature=ABC8ACF6899C46CC992ECB5F6A6FD7E66383EA3D.0C8B707083203DC1153FB26586A94BFAC64D176B&factor=1.25&id=d50e6528eb51ad54");
$max = 0;
$highestLink = "";
foreach ($links as $link) {
$data = explode(",", strrev($link));
$val = strrev($data[0]);
if (is_numeric($val)) {
$val = (int) $val;
if ($val > $max) {
$max = $val;
$highestLink = $link;
}
}
}
echo $max;
For the obfuscation award:
array_multisort(
array_map('intval',preg_replace('/^.*?(,([0-9]+))?$/','$2',$array)),
$array);
echo end($array);

Categories