how to order string from HTTP_ACCEPT_LANGUAGE [duplicate] - php

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
HTTP_ACCEPT_LANGUAGE
i try to code a language option tool. therefor i use
$default_language = (strtolower($_SERVER["HTTP_ACCEPT_LANGUAGE"]));
if (eregi('af', $default_language)) {do something}
now i would like to order the string when i will echo:
$_SERVER["HTTP_ACCEPT_LANGUAGE"]
for example an user has specified a number of languages.
example for chrome with different languages:
nl,en-gb;q=0.8,en;q=0.6,fr;q=0.4,fr-ca;q=0.2
so how can i read out the string to bring it in a certain order where i can see that nl is the first language that is prefered.
the code should be something like:
if ('nl'== array[0]) {do something}
so if there is someone who could help me out i really would appreciate.
thanks alot.

From HTTP/1.1 Header Field Definitions:
Each language-range MAY be given an associated quality value which represents an estimate of the user's preference for the languages specified by that range. The quality value defaults to "q=1".
You have to loop over languages and select one with highest quality (preferrence); like this:
$preferred = "en"; // default
if(isset($_SERVER["HTTP_ACCEPT_LANGUAGE"]))
{
$max = 0.0;
$langs = explode(",", $_SERVER["HTTP_ACCEPT_LANGUAGE"]);
foreach($langs as $lang)
{
$lang = explode(';', $lang);
$q = (isset($lang[1])) ? ((float) $lang[1]) : 1.0;
if ($q > $max)
{
$max = $q;
$preferred = $lang[0];
}
}
$preferred = trim($preferred);
}
// now $preferred is user's preferred language
If Accept-Language header is not sent, all languages are equally acceptable.

How about explode()?
$array = explode(",",$_SERVER["HTTP_ACCEPT_LANGUAGE"]);
Given your example string, you should end up with the following values
$array[0] = "nl"
$array[1] = "en-gb;q=0.8"
$array[2] = "en;q=0.6"
etc.

If you prefer to assume that the string is not always ordered before it is sent by the browser then the following code will parse and sort it. Note that I've changed French's q to 0.9.
<?php
$lang = 'nl,en-gb;q=0.8,en;q=0.6,fr;q=0.9,fr-ca;q=0.2';
$langs = array();
foreach(explode(',', $lang) as $entry) {
$t1 = explode(';', $entry);
switch( count($t1) ) {
case 1:
$langs[] = array($t1[0], 1.0);
break;
case 2:
$t2 = explode('=', $t1[1]);
$langs[] = array($t1[0], floatval($t2[1]));
break;
default:
echo("what is this I don't even");
break;
}
}
function mysort($a, $b) {
if( $a[1] == $b[1] ) { return 0; }
elseif( $a[1] > $b[1] ) { return -1; }
else { return 1; }
}
usort($langs, 'mysort');
var_dump($langs);
Output:
array(5) {
[0]=>
array(2) {
[0]=>
string(2) "nl"
[1]=>
float(1)
}
[1]=>
array(2) {
[0]=>
string(2) "fr"
[1]=>
float(0.9)
}
[2]=>
array(2) {
[0]=>
string(5) "en-gb"
[1]=>
float(0.8)
}
[3]=>
array(2) {
[0]=>
string(2) "en"
[1]=>
float(0.6)
}
[4]=>
array(2) {
[0]=>
string(5) "fr-ca"
[1]=>
float(0.2)
}
}

try this :
<?php
print_r(Get_Client_Prefered_Language(true, $_SERVER['HTTP_ACCEPT_LANGUAGE']));
function Get_Client_Prefered_Language ($getSortedList = false, $acceptedLanguages = false)
{
if (empty($acceptedLanguages))
$acceptedLanguages = $_SERVER["HTTP_ACCEPT_LANGUAGE"];
// regex borrowed from Gabriel Anderson on http://stackoverflow.com/questions/6038236/http-accept-language
preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $acceptedLanguages, $lang_parse);
$langs = $lang_parse[1];
$ranks = $lang_parse[4];
// (recursive anonymous function)
$getRank = function ($j)use(&$getRank, &$ranks)
{
while (isset($ranks[$j]))
if (!$ranks[$j])
return $getRank($j + 1);
else
return $ranks[$j];
};
// (create an associative array 'language' => 'preference')
$lang2pref = array();
for($i=0; $i<count($langs); $i++)
$lang2pref[$langs[$i]] = (float) $getRank($i);
// (comparison function for uksort)
$cmpLangs = function ($a, $b) use ($lang2pref) {
if ($lang2pref[$a] > $lang2pref[$b])
return -1;
elseif ($lang2pref[$a] < $lang2pref[$b])
return 1;
elseif (strlen($a) > strlen($b))
return -1;
elseif (strlen($a) < strlen($b))
return 1;
else
return 0;
};
// sort the languages by prefered language and by the most specific region
uksort($lang2pref, $cmpLangs);
if ($getSortedList)
return $lang2pref;
// return the first value's key
reset($lang2pref);
return key($lang2pref);
}

The languages are ordered as the user prefers them. All you have to do is to split the string at the , symbol and from the parts, get rid off everything from the ; to the end (including the ;) and you have the languages in the user's prefered order.

Related

how to add child array with dynamic key in loop PHP

i have string like this
$string = 'root.1.child1.2.nextnode.3.anothernode.4.var';
exploded by "." and created array like this
$arr = array('root','1','child1','2','nextnode','3','anothernode','3','var');
how i can convert this array to something like this ?
it should be dynamically convert because in some cases nodes in string are in a number different with the sample .
["root"]=>
array(1) {
[1]=>
array(1) {
["child1"]=>
array(1) {
[2]=>
array(1) {
["nextnode"]=>
array(1) {
[3]=>
array(1) {
["anothernode"]=>
array(1) {
[3]=>
array(1) {
[var]=>
NULL
}
}
}
}
}
}
}
}
An example using recursive function.
$array = ['root', '1', 'child1', '2', 'nextnode', '3', 'anothernode', '3', 'var'];
function getNestedArray(array $arr, int $idx = 0) {
if ($idx + 1 <= count($arr)) {
return [$arr[$idx] => getNestedArray($arr, $idx + 1)];
}
return null;
}
$output = getNestedArray($array);
var_dump($output);
This can be quit easily achieved by referencing the output and looping over the exploded array:
$output = [];
$reference = &$output;
foreach ($arr as $el) {
if (is_numeric($el)) {
$el = (int)$el;
}
$reference = [];
$reference[$el] = null;
$reference = &$reference[$el];
}
This also checks whether the element is a number and casts it to an integer if it is. The $output variable will contain the final array.
You can use recursive function
to do though
$flatArray = array('root','1','child1','2','nextnode','3','anothernode','3','var'); // your array
function createNestedArray($flatArray)
{
if( sizeof($flatArray) == 1 ) {
return [ $flatArray[0] => null ]; // for the case that paramter has one member we need to return [ somename => null ]
}
$nestedArray[ $flatArray[0] ] = createNestedArray(array_slice($flatArray, 1)); // otherwise we need to call createNestedArray with rest of array
return $nestedArray;
}
$nestedArray = createNestedArray($flatArray); // the result

How to find similar text in a large string?

I have a large string str and a needle ndl. Now, I need to find similar text of ndl from the string str. For example,
SOURCE: "This is a demo text and I love you about this".
NEEDLE: "I you love"
OUTPUT: "I love you"
SOURCE: "I have a unique idea. Do you need one?".
NEEDLE: "a unik idia"
OUTPUT: "a unique idea"
I found that I can do this using similarity measures like cosine or manhatton similarity measure. However, I think implementation of this algorithms will be difficult. Would you please suggest me any easy or fastest way to do this maybe using any library function of php? TIA
There is no PHP native function to achieve this goal.However the possibilities of PHP is just limited by your imagination.We can't on SO suggest libraries to achieve your goal and you need to keep in mind that this kind of questions can be flagged as off-topic. So instead of suggesting some libraries I will just point you into the directions you need to explore.
As designed ,your question suggest that you don't need simple strings match functions like stripos and co and a regex can't achieve this. For examples
unik and unique
and also
idia and idea
can't be matched by those functions. So You need to look for something like levenshtein function.But as you need sub strings and not necessarly the whole string and also ,in order to make the work easier for the levenshtein function and your server, You need to use some imagination.You could for example break both haystack and needle in words and then use levenshtein to find most closest values to your needles.
This is one way to achieve this .Read carefully the comments to understand the idea and you will be able to implement something better.
for strings with only ASCII chars it is relatively easy to achieve it. But for other Encodings you will probably encounter many difficulties.But a simple approach to handle multibyte strings too could be something like:
function to_ascii($text,$encoding="UTF-8") {
if (is_string($text)) {
// Includes combinations of characters that present as a single glyph
$text = preg_replace_callback('/\X/u', __FUNCTION__, $text);
}
elseif (is_array($text) && count($text) == 1 && is_string($text[0])) {
// IGNORE characters that can't be TRANSLITerated to ASCII
$text = #iconv($encoding, "ASCII//IGNORE//TRANSLIT", $text[0]);
// The documentation says that iconv() returns false on failure but it returns ''
if ($text === '' || !is_string($text)) {
$text = '?';
}
elseif (preg_match('/\w/', $text)) { // If the text contains any letters...
$text = preg_replace('/\W+/', '', $text); // ...then remove all non-letters
}
}
else { // $text was not a string
$text = '';
}
return $text;
}
function find_similar($needle,$str,$keep_needle_order=false){
if(!is_string($needle)||!is_string($str))
{
return false;
}
$valid=array();
//get encodings and words from haystack and needle
setlocale(LC_CTYPE, 'en_GB.UTF8');
$encoding_s=mb_detect_encoding($str);
$encoding_n=mb_detect_encoding($needle);
mb_regex_encoding ($encoding_n);
$pneed=array_filter(mb_split('\W',$needle));
mb_regex_encoding ($encoding_s);
$pstr=array_filter(mb_split('\W',$str));
foreach($pneed as $k=>$word)//loop trough needle's words
{
foreach($pstr as $key=>$w)
{
if($encoding_n!==$encoding_s)
{//if $encodings are not the same make some transliteration
$tmp_word=($encoding_n!=='ASCII')?to_ascii($word,$encoding_n):$word;
$tmp_w=($encoding_s!=='ASCII')?to_ascii($w,$encoding_s):$w;
}else
{
$tmp_word=$word;
$tmp_w=$w;
}
$tmp[$tmp_w]=levenshtein($tmp_w,$tmp_word);//collect levenshtein distances
$keys[$tmp_w]=array($key,$w);
}
$nominees=array_flip(array_keys($tmp,min($tmp)));//get the nominees
$tmp=10000;
foreach($nominees as $nominee=>$idx)
{//test sound like to get more precision
$idx=levenshtein(metaphone($nominee),metaphone($tmp_word));
if($idx<$tmp){
$answer=$nominee;//get the winner
}
unset($nominees[$nominee]);
}
if(!$keep_needle_order){
$valid[$keys[$answer][0]]=$keys[$answer][1];//get the right form of the winner
}
else{
$valid[$k]=$keys[$answer][1];
}
$tmp=$nominees=array();//clean a little for the next iteration
}
if(!$keep_needle_order)
{
ksort($valid);
}
$valid=array_values($valid);//get only the values
/*return the array of the closest value to the
needle according to this algorithm of course*/
return $valid;
}
var_dump(find_similar('i knew you love me','finally i know you loved me and all my pets'));
var_dump(find_similar('I you love','This is a demo text and I love you about this'));
var_dump(find_similar('a unik idia','I have a unique idea. Do you need?'));
var_dump(find_similar("Goebel, Weiss, Goethe, Goethe und Goetz",'Weiß, Goldmann, Göbel, Weiss, Göthe, Goethe und Götz'));
var_dump(find_similar('Ḽơᶉëᶆ ȋṕšᶙṁ ḍỡḽǭᵳ ʂǐť ӓṁệẗ, ĉṓɲṩḙċťᶒțûɾ ấɖḯƥĭṩčįɳġ ḝłįʈ',
'Ḽơᶉëᶆ ȋṕšᶙṁ ḍỡḽǭᵳ ʂǐť ӓṁệẗ, ĉṓɲṩḙċťᶒțûɾ ấɖḯƥĭṩčįɳġ ḝłįʈ, șếᶑ ᶁⱺ ẽḭŭŝḿꝋď ṫĕᶆᶈṓɍ ỉñḉīḑȋᵭṵńť ṷŧ ḹẩḇőꝛế éȶ đꝍꞎôꝛȇ ᵯáꞡᶇā ąⱡîɋṹẵ.'));
and the output is:
array(5) {
[0]=>
string(1) "i"
[1]=>
string(4) "know"
[2]=>
string(3) "you"
[3]=>
string(5) "loved"
[4]=>
string(2) "me"
}
array(3) {
[0]=>
string(1) "I"
[1]=>
string(4) "love"
[2]=>
string(3) "you"
}
array(3) {
[0]=>
string(1) "a"
[1]=>
string(6) "unique"
[2]=>
string(4) "idea"
}
array(5) {
[0]=>
string(6) "Göbel"
[1]=>
string(5) "Weiss"
[2]=>
string(6) "Goethe"
[3]=>
string(3) "und"
[4]=>
string(5) "Götz"
}
array(8) {
[0]=>
string(13) "Ḽơᶉëᶆ"
[1]=>
string(13) "ȋṕšᶙṁ"
[2]=>
string(14) "ḍỡḽǭᵳ"
[3]=>
string(6) "ʂǐť"
[4]=>
string(11) "ӓṁệẗ"
[5]=>
string(26) "ĉṓɲṩḙċťᶒțûɾ"
[6]=>
string(23) "ấɖḯƥĭṩčįɳġ"
[7]=>
string(9) "ḝłįʈ"
}
if you need the output as string you can use join on the result of the function before use it
You can run the working code and check the result online
But you must keep in mind that this will not work for all kind of strings nor for all PHP versions
Try this code to find string within string
$data = "I have a unique idea. Do you need one?";
$find = "a unique idea";
$start = strpos($data, $find);
if($start){
$end = $start + strlen($find);
print_r(substr($data, $start, strlen($find)));
} else {
echo "not found";
}
This is a very easy way to do that:
$source = "This is a demo text and I love you about this";
$needle = "I you love";
$words = explode(" " , $source);
$needleWords = explode(" ", $needle);
$results = [];
foreach($needleWords as $key => $needleWord) {
foreach($words as $keyWords => $word) {
if(strcasecmp($word, $needleWord) == 0) {
$results[$keyWords] = $needleWord;
}
}
}
uksort($results, function($a , $b) {
return $a - $b;
});
echo(implode(" " , $results));
Output
I love you
Use this function it checks any length string
function sim($aa,$bb){
$l1 = strlen($aa);
$l2 = strlen($bb);
if ($l1 > $l2) {
$a = $bb;
$b = $aa;
}else{
$a = $aa;
$b = $bb;
}
// Format string
$a = explode(" ", implode(" ", array_unique(explode(" ", preg_replace("~\b[a-z]{1,2}\b\s*~", "", $a)))));
$b = explode(" ", implode(" ", array_unique(explode(" ", preg_replace("~\b[a-z]{1,2}\b\s*~", "", $b)))));
sort($a);
sort($b);
$a = implode(" ",$a);
$b = implode(" ",$b);
$a = strtolower(preg_replace("/[^A-Za-z0-9\-]/", " ", $a));
$b = strtolower(preg_replace("/[^A-Za-z0-9\-]/", " ", $b));
$dc2 = count(array_diff(str_split($a,2),str_split($b,2)));
$cA1 = count(str_split($a));
$cB1 = count(str_split($b));
$a = explode(" ",$a);
$b = explode(" ",$b);
$dc = count(array_diff($a, $b));
$cA = count($a);
$cB = count($b);
// Calculate similarity
$p = (((($cA + $cB) / 2) - $dc) * 100) / (($cA + $cB) / 2);
$p2 = ((((($cA1 / 2) + ($cB1 / 2)) / 2) - $dc2) * 100) / ((($cA1 / 2) + ($cB1 / 2)) / 2);
$percent = ($p + $p2) / 2;
echo $percent . " %";
}

how to use php to loop through array to validate the value

I have this array
array(6) {
[0]=>
string(7) "1234567"
[1]=>
string(5) "7548#"
[2]=>
string(9) "1254#abc#"
[3]=>
string(5) "32514"
[4]=>
string(6) "2548##"
[5]=>
string(5) "3258#"
}
I want to validate this data based on provided condition.
If ID(array[0] and array[3] or array[n]) is an integer check the *data* which is(array[1] and array[4] or array[n]) and if that data not contain more then one #, return false;
here is my sample code, but I'm only able to check the first and 2nd array,
if(preg_match('/^[1-7]{1,7}$/', current($arr))){
next($arr);
if(substr_count(next($arr),"#") <=1)
//false
else
echo "true";
}
help needed, thanks.
You can use a for loop, which allows you to control the start point, the condition when to stop and the step your using, so...
$arr = ["1234567", "7548#", "1254#abc#", "32514", "2548##", "3258#"];
for ( $i = 0; $i < count($arr); $i+=3) {
echo $arr[$i].PHP_EOL;
if ( preg_match('/^[1-7]{1,7}$/', $arr[$i]) ) {
if(substr_count($arr[$i+1],"#") > 1) { // Check if it's +1 or +2 here
echo "true".PHP_EOL;
}
else {
echo "false".PHP_EOL;
}
}
}
This loops from the start to the number of elements in your source, but just every 3rd item.
The rest uses similar code to what you've already got, but using the array elements relative to the loop counter ($arr[$i+1] for example). You will have to check if this is the right element you want to check as it may be $arr[$i+2], but the concept is the same.
This outputs..
1234567
false
32514
true
One thing I would recommend is to try and write if statements so that you always get something from it being 'true'. In your code you use <=1 and then there is nothing to do - if you change that round to >1, then it means you can get rid of the 'empty' statement.
you need to create a loop then you can write your rules for specific n.
$n = 3; //Your modulo
for($x = 0, $l = count($array); $x < $l; $x++ ) { //$array is your array
if($x % $n == 0) {
$result = preg_match('/^[1-7]{1,7}$/',$array[$x]);
} else if ($x % $n == 1) {
$result = substr_count($array[$x], '#') > 1;
} else {
$result = true; //no specific rule
}
if(!$result) { //if validation fails
echo "Validation failed";
break;
}
}

Multiply and add 2 arrays

I have two variables one named $corp_resp:
var_dump($corp_resp)
string(3) "0.3" string(4) "0.35" string(3) "0.4"
Other: $corp_resp_template
var_dump($corp_res_template)´
string(3) "0.4" string(3) "0.6" string(3) "0.8"
I want to add and multiply the arrays:
$total = (0.3*0.4)+(0.35*0.6) +(0.4*0.8) => 0,12+0.21+0,32
$total = 0.65
What is the best way to do that?
if both your arrays have the same length you can run something like:
array_sum(array_map(
function($resp, $tpl){ return $resp * $tpl; },
$corp_resp, $corp_res_template));
If the arrays are of unequal length, the tail of the longer array will be evaluated to (number * 0) therefore ignoring them when adding up the final result
Write a function to do it
$corp_resp = array("0.3", "0.35", "0.4");
$corp_res_template = array("0.4", "0.6", "0.8");
function add_products($a1, $a2) {
if (!is_array($a1)) {
throw new Exception("a1 is not an array");
}
if (!is_array($a2)) {
throw new Exception("a2 is not an array");
}
if (sizeof($a1) != sizeof($a2)) {
throw new Exception("Arrays don't have same number of elements");
}
// both params are arrays and have same number of elements!
$count = sizeof($a1);
$multiplied = array();
for($i=0; $i<$count; $i++) {
// we assume that each element is a string representing a floatval so we need to cast as a float before multiplying
$multiplied[$i] = floatval($a1[$i]) * floatval($a2[$i]);
}
return array_sum($multiplied);
}
$val = add_products($corp_resp, $corp_res_template);
var_dump($val);

How to make an average of array values

I have a database with multiple records. It is structured like this:
["data"]=>
array(5) {
[1]=>
[2]=>
array(11) {
[0]=>
string(1) "0"
[1]=>
string(8) "25000000"
[2]=>
string(3) "day"
[3]=>
string(5) "0.00%"
[4]=>
string(9) "404049904"
[5]=>
string(1) "0"
[6]=>
string(5) "0.00%"
[7]=>
string(1) "0"
[8]=>
string(1) "0"
[9]=>
string(1) "0"
[10]=>
string(3) "0.0"
}
I need to fetch the 8th record and I do this by using
public static function($data)
{
$array = [];
$path = $data->data[2];
foreach($path as $key => $item)
if($key > 1)
{
$array[] = [$item->data[8]];
}
return json_encode($array);
}
This foreach takes all the 8th values from the array but I need to display a single number which is the average of all the 8th values. How can I do this?
Once you've got your array containing all your data, simple sum the array and then divide by the size of the array.. something along these lines
$average = (array_sum($array) / count($array));
Of course you may want to check for count($array) being 0;
Because you put your value into a new array, you can not use array_sum to sum the values, so you should store it.
$sum = 0;
foreach($path as $key => $item)
if($key > 1) {
$array[] = [$item->data[8]];
$sum += $item->data[8];
}
}
$avg = ($sum / count($array); //the average
var_dump($avg);
If is it possible, just put it as a value:
$array[] = $item->data[8]; //no wrapping []
In this case, you can use $avg = array_sum($array) / count($array);
if (count($array)>0){
$avg = array_sum($array) / count($array);
}
I would personally do those calculations in the database before the data gets to your PHP script itself. See AVG().
If you can't for some reason use that I would output those values into a flat array and then just calculate the average. So something like :
function getAverage($data) {
$flatArray = array();
foreach ($data as $row) {
if (!empty($row->8)) {
$flatArray[] = $row->8;
}
}
return (array_sum($flatArray)/count($flatArray));
}
EDIT: Moved to Object traversing on the data row, sorry, missed that initially and thought it was an array in all the nests.
Since you have a loop within your static Method; why not do the calculation therein and return it or add it to the JSON Data if You need your Data in JSON Format? Here's what's implied by the above:
public static function getAverageSum($data) {
$array = [];
$path = $data->data[2];
$sumTotal = 0.00; //<== YOU COULD JUST SUM IT DIRECTLY WITHOUT USING AN ARRAY
foreach($path as $key => $item) {
if ($key > 1) {
$array[] = $item->data[8];
$sumTotal += floatval($item->data[8]);
}
}
// IF YOU ARE ONLY INTERESTED IN THE AVERAGE SUM YOU COULD EVEN ADD IT IT TO THE $array AS AN EXTRA KEY
// LIKE SO:
$arrLen = count($array);
$array['avgSum'] = $sumTotal/$arrLen;
// IF YOU NEED YOUR DATA IN JSON... THEN RETURN THE JSON ENCODED DATA WITH SUM AS PART OF THE DATA.
// YOU'D HAVE NO NEED FOR array_sum() SINCE YOU DID YOUR PREP-WORK ALREADY...
return json_encode($array);
// ALTERNATIVELY; IF ALL YOU NEED IS JUST THE AVERAGE SUM; YOU COULD AS WELL DIRECTLY RETURN $sumTotal/$arrLen
return ($sumTotal/$arrLen);
}

Categories