PHP str_replace bug - php

I'm running simple PHP code
$myVariable = 1;
$myVariable2 = str_replace(array(1, 2, 3), array('do 25 lat', 'od 26 do 35 lat', 'pow. 35 r.z.'), $myVariable);
echo $myVariable2;
And result is:
do od 26 do pow. 35 r.z.5 lat5 lat
I checked on different PHP versions. Any ideas?

You're falling victim to the gotcha specified in the documentation - look under "notes" on the str_replace documentation
Replacement order gotcha
Because str_replace() replaces left to right, it might replace a previously inserted value when doing multiple replacements. See also the examples in this document.
Essentially what's happening is the sequential replacements, as you passed an array as the second parameter:
1 is replaced with do 25 lat
In that string, 2 is replaced with od 26 do 35 lat, giving you do od 26 do 35 lat5 lat
In that string, 3 is replaced with pow. 35 r.z. giving you the final result you're seeing.

This is because str_replace array pairs are applied one after the other.
Try strtr:
$myVariable = 1;
$replacePairs = array(
1 => "do 25 lat",
2 => "od 26 do 35 lat",
3 => "pow. 35 r.z."
);
$myVariable2 = strtr($myVariable,$replacePairs);
echo $myVariable2;

It's not a bug, this is the normal behavior of str_replace. What happens is the function iterates through your search array and each time it finds an occurrence, it replaces it with relevant replace.
Thus:
(search and match 1) 1 -> "do 25 lat"
(search and match 2) "do 25 lat" -> "do od 26 do 35 lat5 lat"
(search and match 3) "do od 26 do 35 lat5 lat" -> "do od 26 do pow. 35 r.z.5 lat5 lat"

Related

Embed URL to coordinates, kml or geojson

I've got a complex directions URL and embed URL that I would like to get polylines for. Once I can get them into polylines or something similar I can convert to final format: GeoJSON.
Direction Link
-or-
Embed Link
I have looked at the API's and I can't find anything that accepts or would decode the PB (what is this? it's not a protocol buffer). So far this is as far as I've got:
//php
$pb_array = explode('!', $pb);
foreach($pb_array as $key => $value){
echo "$key - $value<br/>";
}
===
1 - 1m73
2 - 1m12
3 - 1m3
4 - 1d1472548.9575794793
5 - 2d-72.8191002664707
6 - 3d43.87505426780168
7 - 2m3
8 - 1f0
9 - 2f0
10 - 3f0
11 - 3m2
12 - 1i1024
13 - 2i768
14 - 4f13.1
15 - 4m58
16 - 3e0
17 - 4m5
18 - 1s0x0%3A0xa58b3d6041ba69f8
19 - 2sGuilford+Welcome+Center
20 - 3m2
21 - 1d42.8120069
22 - 2d-72.56614689999999
23 - 4m3
24 - 3m2
25 - 1d43.3893165
26 - 2d-72.40772249999999
27 - 4m5
28 - 1s0x4cb52e78df455c83%3A0xb6946ec850907db8
29 - 2s130+Lower+Michigan+Road%2C+Pittsfield%2C+VT+05762
30 - 3m2
31 - 1d43.76898
32 - 2d-72.815214
33 - 4m4
34 - 1s0x0%3A0xea2de48bba82cc86
35 - 3m2
36 - 1d44.042544
37 - 2d-72.6046997
38 - 4m5
39 - 1s0x0%3A0x6bb602ed58bf4413
40 - 2sJay+Peak+Resort
41 - 3m2
42 - 1d44.9379515
43 - 2d-72.5045433
44 - 4m5
45 - 1s0x4cb392aaa4333a07%3A0x160aef1559868340
46 - 2sDolly+Copp+Campground+Rd%2C+Gorham%2C+NH+03581
47 - 3m2
48 - 1d44.335842199999995
49 - 2d-71.21837339999999
50 - 4m5
51 - 1s0x4cb392684201a94d%3A0xfa4a6f490a05429d
52 - 2sMt+Washington+Auto+Road%2C+1+Mount+Washington+Auto+Road%2C+Gorham%2C+NH+03581
53 - 3m2
54 - 1d44.288384099999995
55 - 2d-71.22459599999999
56 - 4m5
57 - 1s0x4cb38e798f42c3d9%3A0xc3b88e4dac01db12
58 - 2sMt+Washington
59 - 3m2
60 - 1d44.270585399999995
61 - 2d-71.3032723
62 - 4m5
63 - 1s0x89e2a7fa444124d5%3A0xe3ed24b6f864eba0
64 - 2sWells%2C+ME
65 - 3m2
66 - 1d43.322232899999996
67 - 2d-70.5805209
68 - 4m5
69 - 1s0x89e2ba813e828c71%3A0x8cdf74380f6a933d
70 - 2sLibby's+Oceanside+Camp%2C+York+Street%2C+York%2C+ME
71 - 3m2
72 - 1d43.147162
73 - 2d-70.626173
74 - 5e1
75 - 3m2
76 - 1sen
77 - 2sus
78 - 4v1472497940601
The closest hints I could find are from this thread. I will keep looking but I'm stuck.
I'm trying to create an API based solution that has an input of one of these URL's and returns a GeoJSON.
would decode the PB (what is this? it's not a protocol buffer)
For the record, because this overflow question keeps popping up on google results: it is a protocol buffer. PB litteraly stands for protocol buffer.
It's just a different ASCII encoding (a compact URL encoding reminiscent of the binary encoding, not the usual JSON-like text encoding. When you squint at it it's not that much different than torrent's structure encoding), and Google doesn't provide us the .proto file.
For each field:
first character is the id (identifies the field according to the corresponding .proto file)
second character is the type of the field
m is for message
s is for string
i, j, u, v are for various type of ints
f, d are for floating points
e is for enum
the rest is the payload
So to unpack the fields you're seeing (even if we don't have the .proto file):
1m73 message of type 1, containing 73 elements (the whole message set)
1m12 submessage of type 1, contains 12 elements (probably information about the view box in the map box)
1m3 sub-sub-message type 1, contains 3 elements (probably map coordinates)
1d1472548.9575794793 first double field (probably zoom level)
2d-72.8191002664707 second double field (probably longitude)
3d43.87505426780168 third double field (probably latitude)
2m3 second sub-sub-sub message (no idea given that it's not filled. Maybe a starting point if you code a route instead of a single point ?)
1f0, 2f0, 3f0 the three members, currently just zero
3m2 third block (looks like a screen resolution)
1i1024, 2i768 : 1024x768 ? (and probably the omited field 3 would have been the color depth if present ??)
4f13.1 no idea, but it's a float
4m58 next message with 58 elements (to me it looks like a bunch of POI that we need to display in the box)
3e0 an enum, set to zero (this one would be completely impossible to interpret without a proto or without experimenting, as you need the list of enums)
4m5 five more elements probably a map poi
- 1s0x0%3A0xa58b3d6041ba69f8 string '0x0:0xa58b3d6041ba69f8', note the use of Url_encoded character. In turn it looks like a pair of hex numbers, maybe a GUID ?
- 2sGuilford+Welcome+Center string, the name with plus instead of blank (like most URLs)
- 3m2 two elements to come
- 1d42.8120069 and 2d-72.56614689999999 doubles probably map coordinates
4m3 again a message of type 4 in this level, so probably another poi
- 3m2, 1d43.3893165, 2d-72.40772249999999 but this one only specifies coordinates, and nothing else
4m5 another poi
- 1s0x4cb52e78df455c83%3A0xb6946ec850907db8 different pair of hex, GUID
...you got the idea...
5e1 another bunch of information probably general settings
3m2 this setting is a message (and looks like a locale)
1sen, 2sus locale is en_US
4v1472497940601 some other large number...
Note: the original proto that Google doesn't show us, is probably a single multi level structure. Thus, the sub-sub-message ID don't have always the same meaning: they aren't global ID, but ID within the parent message.
inside a sub message ID 1 (view box ?), the sub-sub message 3 seems to be resolution.
inside a sub message ID 4 (POIs ?), the sub-ID 3 isn't even a message but some enum
inside a sub message ID 5 (parameters), the sub-sub message 3 is a locale
Well, here's my sloppy but working solution. My needs required GeoJSON, but others can use the google maps service to get the desired output once you have the lat/lng array.
$embed = '<iframe src="https://www.google.com/maps/embed?pb=!1m73!1m12!1m3!1d1472548.9575794793!2d-72.8191002664707!3d43.87505426780168!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!4m58!3e0!4m5!1s0x0%3A0xa58b3d6041ba69f8!2sGuilford+Welcome+Center!3m2!1d42.8120069!2d-72.56614689999999!4m3!3m2!1d43.3893165!2d-72.40772249999999!4m5!1s0x4cb52e78df455c83%3A0xb6946ec850907db8!2s130+Lower+Michigan+Road%2C+Pittsfield%2C+VT+05762!3m2!1d43.76898!2d-72.815214!4m4!1s0x0%3A0xea2de48bba82cc86!3m2!1d44.042544!2d-72.6046997!4m5!1s0x0%3A0x6bb602ed58bf4413!2sJay+Peak+Resort!3m2!1d44.9379515!2d-72.5045433!4m5!1s0x4cb392aaa4333a07%3A0x160aef1559868340!2sDolly+Copp+Campground+Rd%2C+Gorham%2C+NH+03581!3m2!1d44.335842199999995!2d-71.21837339999999!4m5!1s0x4cb392684201a94d%3A0xfa4a6f490a05429d!2sMt+Washington+Auto+Road%2C+1+Mount+Washington+Auto+Road%2C+Gorham%2C+NH+03581!3m2!1d44.288384099999995!2d-71.22459599999999!4m5!1s0x4cb38e798f42c3d9%3A0xc3b88e4dac01db12!2sMt+Washington!3m2!1d44.270585399999995!2d-71.3032723!4m5!1s0x89e2a7fa444124d5%3A0xe3ed24b6f864eba0!2sWells%2C+ME!3m2!1d43.322232899999996!2d-70.5805209!4m5!1s0x89e2ba813e828c71%3A0x8cdf74380f6a933d!2sLibby's+Oceanside+Camp%2C+York+Street%2C+York%2C+ME!3m2!1d43.147162!2d-70.626173!5e1!3m2!1sen!2sus!4v1472497940601" width="600" height="450" frameborder="0" style="border:0" allowfullscreen></iframe>';
$array = array();
preg_match( '/src="([^"]*)"/i', $embed, $array ) ;
list($pre, $pb) = split("pb=", $array[1]);
if($pb == "" || strpos($pb, "!") === false)
die(json_encode(array("success"=>false)));
//echo "PB Extracted:<br>";
//echo $pb;
///echo "<br><br>Decode:<br/>";
$pb_array = explode('!', $pb);
$coords = array();
$address;$addressHex;
$results = array();
foreach($pb_array as $key => $value){
//uncomment to debug output
//echo "$key - $value<br/>";
if($value == "3m2" || $value == "2m2"){
//3m2 seems to be the divider of these 'places'
if(count($coords) != 3) //don't add the center of map data (3 coordinates [height, lng, lat])
array_push($results, array("coords"=>$coords,"address"=>$address,"addressHex"=>$addressHex));
$coords = array(); //reset array
}else{
$type = substr($value, 1, 1);
$stype = substr($value, 0, 2);
$value = substr($value, 2);
//echo "$type - $value<br/>";
if($type == "d"){
//Found Lat,Lng
array_push($coords, $value);
}else if($stype == "2s"){
//Address
$address = $value;
}else if($stype == "1s"){
//Address Encoded in some way
$addressHex = $value;
}
}
}
//echo "<br><br>Google Result<br/>";
//echo json_encode($results);
//echo "<br><br>Mapbox API:<br/>";
$waypoints = array();
for($i=0;$i<count($results);$i++){
if(count($results[$i]["coords"])){
$lat = $results[$i]["coords"][0];
$lng = $results[$i]["coords"][1];
array_push($waypoints, "$lng%2C$lat");
}
}
$waypoints = implode("%3B", $waypoints); //convert to string
$mapbox_api_key = "pk.eyJ1I.....";
$url = "https://api.mapbox.com/directions/v5/mapbox/driving/$waypoints.json?steps=false&alternatives=false&overview=full&geometries=geojson&access_token=$mapbox_api_key";
//echo "<br><br>Mapbox Response:<br/>";
$response = file_get_contents($url);
$json = json_decode($response,true);
//echo "<br><br>Mapbox Geometry:<br/>";
$coordinates = $json["routes"][0]["geometry"]["coordinates"];
$geojson = (array("type"=>"FeatureCollection","features"=>array(array("type"=>"Feature","geometry"=>array("type"=>"LineString","coordinates"=>$coordinates),"properties"=>array()))));
echo json_encode(array("success"=>true, "geojson"=>$geojson));

Fetch value from text file using preg_match PHP

I have a text file in following format.
Wed Aug 27 20:24:53.536 IST
address ref clock st when poll reach delay offset disp
*~172.16.18.163 .GPS. 1 657 1024 377 13.99 1.801 19.630
~127.127.1.1 .LOCL. 3 15 64 377 0.00 0.000 1.920
* sys_peer, # selected, + candidate, - outlayer, x falseticker, ~ configured
file has been generated dynamically I need to fetch value of 'st' (1) value next to '.GPS.' . text '.GPS.' is going to be same in every file.
Check my following code:
$f1_content = file_get_contents('filename.txt');
if(preg_match("/\b(.*)\s(.*)\s[0-9]\s\b/i", $f1_content, $match))
{
print_r($match); die();
}
not getting any match. Any idea how it can be done?
You can follow this:
#\.GPS\.\s+\K(\d+)#is
PHP:
preg_match("#\.GPS\.\s+\K(\d+)#is", $f1_content, $match)
If you may have more than of occurrences of that, you should use preg_match_all
Live demo
(?=.*?\.GPS\.).*?GPS\.\s*(\d+)
Try this.This works.
See demo.
http://regex101.com/r/pP3pN1/12

Mapping Values to 14 categories (Math and permutations stuff)

My app has people put 24 groups of 4 statements in order. In each group of 4 one is the "D" statement, one is the "I" statement, one is the "S" statement, and one is the "C" statement.
So the end result looks something like ['ISCD','CISD','DISC',CISD,'CISD','ISCD'...] because the are essentially rearranging the 4 letters
In the end, they get a "score" for each letter using the following algorithm.
For each of I,S,C and D
Find the number of times that letter is first and multiply by 3
Find the number of times that letter is second and multiply by 2
Find the number of times that letter is third and muliply by 1
Total it up, and that is the score for that letter
The end result is that each letter (I,S,D,C) gets a score from 0 to 72, and there are always 144 total points given out:
I want to map the results to 14 reports:
D
I
S
C
DI
IS
SC
CD
DS
IC
DIS
ISC
SCD
CDI
The idea is that if S is dominant, we choose the S report. If Both D and I are dominant, we choose the DI report. If none is particularly dominant, we choose the top 3. (there is no difference between DI and ID meaning which one is most dominant is irrelevant if they are both high)
So if the scores are D=50, I=48, S=20,C=26 then I want it to choose "DI" since D and I are dominant. There are 24^(4!) possible responses from the user, that I need to map to 14 reports
I understand that I will have to set the thresholds for what "dominant" means, but for starters, I want to assume all possible responses are equally likely, and to map all possible responses to the 14 reports to where each of the 14 reports is equally likely, given random input.
I expect it's 1 to 5 lines of code. It'll be in php but any language including math or pseudo code should be fine.
UPDATE:
I figured out a way to do it in one line of code, but it's not evenly distributed. here's the php (no dependencies)
<?php
$totals=array();
$lets=array('D','I','S','C');
for($j=0;$j<100000;$j++)
{
$vals=array('D'=>0,'I'=>0,'S'=>0,'C'=>0);
for($i=0;$i<24;$i++)
{
shuffle($lets);
$vals[$lets[0]]+=3;
$vals[$lets[1]]+=2;
$vals[$lets[2]]+=1;
}
$D=$vals['D'];$I=$vals['I'];$S=$vals['S'];$C=$vals['C'];
//calculate which report
$reportKey=($D>36?'D':'').($I>36?'I':'').($S>36?'S':'').($C>36?'C':'');
if(!$reportKey)
$reportKey="DIS";
if(isset($totals[$reportKey]))
$totals[$reportKey]+=1;
else
$totals[$reportKey]=1;
echo $reportKey." $D $I $S $C <br>";
}
echo "<br>";
foreach ($totals as $k=>$v)
echo "$k: $v<br>";
The magic line is
$reportKey=($D>36?'D':'').($I>36?'I':'').($S>36?'S':'').($C>36?'C':'');
That line says if any value is over 36, include that letter. the output of the script is like this:
SC 35 33 38 38
IC 33 42 32 37
DI 44 39 29 32
...
...
DC 46 21 35 42
DIS 38 37 40 29
IC 36 39 28 41
DS 41 36 42 25
C 36 34 29 45
IS 29 41 38 36
IS 28 46 41 29
DS 38 33 40 33
DS 41 33 40 30
DS: 1444
D: 889
IS: 1466
S: 910
C: 874
SC: 1442
IC: 1467
DI: 1569
ISC: 407
DSC: 386
DIS: 388
DC: 1487
DIC: 396
I: 875
As you can see, it automatically split it into 14 categories, but the distribution varies with the 2 letter ones being way more likely.
You can do this recursively using Haskell e.g. as follows:
combinationsOf _ 0 = [[]]
combinationsOf [] _ = []
combinationsOf (x:xs) k = map (x:) (combinationsOf xs (k-1) ) ++ combinationsOf xs k
The results from GHCI:
*Main> concatMap (combinationsOf "DISC") [1,2,3]
["D","I","S","C","DI","DS","DC","IS","IC","SC","DIS","DIC","DSC","ISC"]

using PHP to find exact value in a string

the current tasks at hand is using PHP to check if data exists
to make things short the problem is:
i am trying to search some of the available sizes in a unorganized string.
sizes are
SM/M M/L L/XL XS S M L XL XXL 28 30 31 32 33 34 35 36 28 X 30 28 X 32
currently most of the issues are solved by utilizing whitespaces to disgtinush unique variable, but when it comes to (number X number) as a phrase it becomes very difficult.
when I search for "28" it also detect as found when seeing "28 X 30"
or when I search for unique number " 30 " with the whitespaces included, it still detects the 28 X "30"
Is there any method to tackle this issue?
What you could do is make the string easier to deal with by first transforming the nnn X nnn strings and removing spaces from them:
//BEFORE: SM/M M/L L/XL XS S M L XL XXL 28 30 31 32 33 34 35 36 28 X 30 28 X 32
//AFTER: SM/M M/L L/XL XS S M L XL XXL 28 30 31 32 33 34 35 36 28X30 28X32
$sizes=preg_replace('/(\d+) X (\d+)/', '$1X$2', $sizes);
Now you can explode the string on spaces
$sizeArray=explode(' ', $sizes);
With all the distinct sizes in an array, you can use in_array to look for a specific size code.
//we want to find this
$searchFor='28 X 30';
//our codes no longer have spaces...
$searchFor=str_replace(' ', '', $searchFor);
if (in_array($searchFor, $sizeArray)) {
//great!
}

PHP/jQuery/Javascript - Allow only numbers and some characters in variable

I need to verify if user have entered desired characters in the input field and if he didn't, I need to format input like this:
Start variable: +42 88 66 44 3, +42 (4) 87/654321; +42 3 123456
Desired variable: +428866443, +42487654321, +423123456
So basically I need to clear out all characters from variable that are not numbers and allow only signs like + , ; -.
Because I'm using an AJAX request, I would appreciate code for both PHP and Javascript.
For striping invalid chars from your string use regular expression in PHP and JAVASCRIPT.
PHP
$s = '+42 88 66 44 3, +42 (4) 87/654321; +42 3 123456';
$n = preg_replace('~[^\d\+,;-]~', '', $s);
print_r($n);
JAVASCRIPT
var s = '+42 88 66 44 3, +42 (4) 87/654321; +42 3 123456';
var n = s.replace(/[^\d\+,;-]/g, "");
console.log(n);
But better practice is that you show error, if user enters wrong format. You will need some validating to todo...

Categories