need to append to a string in php - php

I have edited my original question because I think made it more complicated than what I need.
Here is what I need to add:
Check if the input for $query has the word hockey in it
if not append hockey to the string
return $query
Here is the portion of the php code that I need to adjust:
public function search($query, $size = 10, $page = 0, $location = '', $miles = 5, $sort = 'rd') {
$params = array(
'q' => rawurlencode(trim($query)),
'sb' => $sort,
'ws' => $size,
'pn' => (intval($page) < 1 ? 0 : intval($page)),
);

You don't need a regex for this; strpos will be faster anyway. Note the triple === sign. (manual)
public function search($query, $size = 10, $page = 0, $location = '', $miles = 5, $sort = 'rd') {
if( strpos( $query, 'hockey' ) === false ) {
$query .= ' hockey';
}
$params = array(
'q' => rawurlencode(trim($query)),
'sb' => $sort,
'ws' => $size,
'pn' => (intval($page) < 1 ? 0 : intval($page)),
);

Use strpos to find the first ocurrence of hockey in the queried string
http://es1.php.net/manual/en/function.strpos.php
The function strpos returns false if the substring (in this case, hockey is not found).
So you can do something like:
if !strpos($query, 'hockey') {
$query = $query . ' hockey';
}

Related

A non well formed numeric value encountered when function inside foreach

For some reason I keep getting this notice when I try to loop through an array and change it's values.
For some reason, the array is passing 2 values, the one before and the one after when running the same function that changes the values.
class UnitConverter {
public $vulgar_to_float = array('½' => '1/2');
public function replaceUnicode($amount){
foreach($this->vulgar_to_float as $key => $float){
if(is_numeric($amount)){
return $amount;
} else if($key === $amount){
return $float;
}
}
}
public function convertAmount($amount, $from, $to){
if($from === 'pound' && $to === 'ounce'){
return $amount * 16;
} else if($from === 'cup' && $to === 'tablespoon'){
print_r($amount); // here it's echoing 2 values when it should be 1
return $this->replaceUnicode($amount) * 16;
} else {
throw new \Exception('Unable to convert ' . $from . ' to ' . $to);
}
}
}
function convertIngredients($arr){
foreach($arr as $key => $value){
if($arr[$key]['unit_name'] === 'pound'){
$arr[$key]['amount'] = (new UnitConverter())->convertAmount($arr[$key]['amount'], 'pound', 'ounce');
$arr[$key]['unit_name'] = 'ounce';
} else if($arr[$key]['unit_name'] === 'cup'){
$arr[$key]['amount'] = (new UnitConverter())->convertAmount($arr[$key]['amount'], 'cup', 'tablespoon');
$arr[$key]['unit_name'] = 'tablespoon';
}
}
return $arr;
}
function generateBreakfast(){
$array = $var = array(
0 => array( 'amount' => 1, 'ingredient_name' => 'almond flour', 'unit_name' => 'cup' ),
1 => array( 'amount' => ½, 'ingredient_name' => 'erythritol', 'unit_name' => 'cup' ),
2 => array( 'amount' => 1, 'ingredient_name' => 'egg', 'unit_name' => 'large' )
);
$converted_ingredients = convertIngredients($array);
return $converted_ingredients;
}
echo '<pre>';
print_r(generateBreakfast());
echo '</pre>';
So in the convertIngredients, we're calling the convertAmount method, but for some reason there.. it's passing this '1½' instead of just calling the method individually with each iteration.
If you take a look here: https://eval.in/944452 , the amount in erythritol is showing 16, but it should be 8 because 1/2 of 16 = 8.
Replace vulgar_to_float with...
public $vulgar_to_float = array('½' => 0.5);
... and it should work.
As it stands, 16 * '1/2' expression is evaluated by the code. You probably hope that PHP automatically 'resolves' the second operand to a correct numeric value. But it doesn't, as the parsing rules (applied to a string in attempt to cast it to a number) don't treat '/' character in any special way - hence it's discarded, along with the rest of string.
That means, value of 16 * '1/2' is essentially equal to 16 * 1 - which is, as you clearly noticed, 16.
The change prevents this error - and makes life for PHP a little bit easier: if you're going to get a float as replaceUnicode return value, use floats in your map right from the start so that the engine won't have to spend time on type juggling.
Kudos to #raina77ow for indicating the necessary correction. I went ahead and reviewed the code and altered it as follows:
<?php
class UnitConverter {
public $vulgar_to_float = ['½' => 0.5];
public function replaceUnicode( $amount = 0 ){
$half = $this->vulgar_to_float['½'];
return ( is_numeric( $amount ) )? $amount : $half;
}
public function convertAmount($amount, $from, $to){
if($from === 'pound' && $to === 'ounce'){
return $amount * 16;
} else if($from === 'cup' && $to === 'tablespoon'){
return $this->replaceUnicode( $amount ) * 16;
} else {
throw new Exception('Unable to convert ' . $from . ' to ' . $to);
}
}
}
function convertIngredients( $arr = null){
$unit_names = array_column($arr, 'unit_name');
foreach($unit_names as $key => $unit){
if( $unit === 'pound'){
$arr[$key]['amount'] = (new UnitConverter())->convertAmount($arr[$key]['amount'], $unit, 'ounce');
$arr[$key]['unit_name'] = 'ounce';
} else if($unit === 'cup'){
$arr[$key]['amount'] = (new UnitConverter())->convertAmount($arr[$key]['amount'], $unit, 'tablespoon');
$arr[$key]['unit_name'] = 'tablespoon';
} else {
continue;
}
}
return $arr;
}
function generateBreakfast(){
$array = [
0 => array( 'amount' => 1, 'unit_name' => 'cup', 'ingredient_name' => 'almond flour' ),
1 => array( 'amount' => '½', 'unit_name' => 'cup', 'ingredient_name' => 'erythritol' ),
2 => array( 'amount' => 1, 'unit_name' => 'large', 'ingredient_name' => 'egg' )
];
return convertIngredients($array);
}
echo '<pre>';
print_r(generateBreakfast());
echo '</pre>';
See live code
There was a place in the code that needed quotes around the unicode one-half symbol. Also, I tried to eliminate unnecessary verbosity. One code statement creates a variable and then returns it whereas this code returns the value. I used a ternary statement and I used array_column() to pinpoint the unit names in a more straightforward fashion.
And, for the cooks among us, more straightforward to show the unit name and the amount followed by the ingredient :)

Loop function until there is no specified needle in the haystack

I'm trying to build a function, that will check if the needle is in haystack, if it is then the function should loop until there is none.
So far I've built a function for random number generation. What that function does is it will create a random string then hash it with sha512. The function then extracts all the numbers from a string and multiplies it by 2.
It leaves me with a long line of numbers, then I'll use mt_rand to specify start and end point for strpos. After that I just return the number that was created randomly.
function randomNumber($suurus, $max){
mb_internal_encoding("UTF-8");
$possible="aábcdeéfghiíjklmnoóöópqrstuúüűvwxyzAÁBCDEÉFGHIÍJKLMNOÓÖŐPQRSTUÚVWXYZ";
$char = mb_substr($possible,rand(0, mb_strlen($possible) - 1),1);
$str = openssl_digest($char, 'sha512');
$str = preg_replace('/[^1-9.]+/', '', $str);
$str = $str*2;
$strLen = strlen($str)-5;
$strStart = mt_rand(1, $strLen);
$strEnd = mt_rand(1, $suurus);
$str = substr($str, $strStart, $strEnd);
while($str > $max){
$str = $str / 2;
}
return round($str);
The thing is that this number can't repeat, I need it to be unique at all times for my app.
I actually accomplished what I wanted with if else statements, but that means I have to write a long script of repeated if statements until I get the results I want. I really don't think this is the smartest way to do things.
if(!isset($voitjad)){
$voitjad[$vCounter][] = array(
'nimi' => $voitja,
'auhind' => $keyCode['v'.$vCount.''],
'rn' => $rN,
'siin' => 1,
'id' => $voitjaID
);
}else{
if(!exist($rN, $voitjad)){
$voitjad[$vCounter][] = array(
'nimi' => $voitja,
'auhind' => $keyCode['v'.$vCount.''],
'rn' => $rN,
'siin' => 1,
'id' => $voitjaID
);
}else{
$rN = randomNumber($atLength, $atCount);
$voitja = $attendcheckfb['attending'][$rN]['name'];
$voitjaID = $attendcheckfb['attending'][$rN]['id'];
if(!exist($rN, $voitjad)){
$voitjad[$vCounter][] = array(
'nimi' => $voitja,
'auhind' => $keyCode['v'.$vCount.''],
'rn' => $rN,
'siin' => 2,
'id' => $voitjaID
);
}else{ and so on....
I also tried with do-while loop, but I couldn't really get it working, I'm not sure what exactly I'm doing wrong here. If you can educate me, shoot me with information.
$nimed = array_values($nimed);
$voitja = $nimed[$rN]['name'];
$voitjaID = $nimed[$rN]['id'];
$voitjad[$vCounter][] = array(
'nimi' => $voitja,
'auhind' => $keyCode['v'.$vCount.''],
'rn' => $rN,
'siin' => 1,
'id' => $voitjaID
);
$oitjaCount++;
$rN = randomNumber($nimedLength, $nimedCount);
} while(!exist($rN, $voitjad));
If there's a way for me to get better randomly generated numbers, then please tell me, I'm open for suggestions. Meanwhile I need help with this needle, haystack thing.
You can either do it with a loop:
function get_unique_hashcode() {
global $hash_array;
do {
$hashcode = make_random_hashcode();
} while (in_array($hashcode, $hash_array));
$hash_array[] = $hashcode;
return $hashcode;
}
Or you can do it with recursion:
function get_unique_hashcode() {
global $hash_array;
$hashcode = make_random_hashcode();
if (in_array($hashcode, $hash_array)) {
return get_unique_hashcode();
} else {
$hash_array[] = $hashcode;
return $hashcode;
}
}
This is just a general structure, you may need to adjust it for your detailed needs.

call_user_func_array with array_multisort [duplicate]

This question already has answers here:
Sort array using array_multisort() with dynamic number of arguments/parameters/rules/data
(5 answers)
Closed 2 years ago.
I have the problem with sort direction. I try to sort multi-dimensional array with direction. I can't use array_multisort() directly, because I don't know how many parametrs will be. I use call_user_func_array('array_multisort', $params); And it works, but I can't set sort direction (SORT_ASC,SORT_DESC). How can I set sort direction for call_user_func_array('array_multisort', $params);?
Here is my code, you can try it
function get_fields($data, $order_by) {
$order_row = preg_split("/[\s,]+/", $order_by);
for ($i=0;$i<count($order_row);$i++) {
foreach ($data as $key => $row) {
$tmp[$i][$key] = $row[$order_row[$i]];
}
}
return $tmp;
}
function ordering($data, $order_by) {
$tmp = get_fields($data, $order_by);
$params = array();
foreach($tmp as &$t){
$params[] = &$t;
}
$params[1] = array("SORT_DESC","SORT_DESC","SORT_DESC","SORT_DESC"); // like that no warning but no sorting
$params[] = &$data;
call_user_func_array('array_multisort', $params);
return array_pop($params);
}
$data = array (
array('id' => 1,'name' => 'Barack','city' => 9),
array('id' => 7,'name' => 'boris','city' => 2),
array('id' => 3,'name' => 'coris','city' => 2),
array('id' => 3,'name' => 'coris','city' => 2)
);
$order_by = "city desc, name";
echo "<br>ORDER BY $order_by<br>";
$ordered = ordering($data, $order_by);
echo "<pre>";
var_dump($ordered);
echo "</pre>";
I want to do a sort like MySQL ORDER BY city DESC, name. It's my goal.
To be able to sort an array multiple times and achieve a result like ORDER BY city DESC, name ASC you need a function that does a stable sort.
As far as I know PHP doesn't have one so you have to sort it once with a comparator function like this
$data = array (
array('id' => 3,'name' => 'coris','city' => 2),
array('id' => 1,'name' => 'Barack','city' => 9),
array('id' => 7,'name' => 'boris','city' => 2),
array('id' => 3,'name' => 'coris','city' => 2),
);
$order_by = array(
'city' => array('dir' => SORT_DESC, 'type' => SORT_NUMERIC),
'name' => array('dir' => SORT_ASC, 'type' => SORT_STRING),
);
function compare($row1,$row2) {
/* this function should determine which row is greater based on all of the criteria
and return a negative number when $row1 < $row2
a positive number when $row1 > $row2
0 when $row1 == $row2
*/
global $order_by;
foreach($order_by as $field => $sort) {
if($sort['type'] != SORT_NUMERIC) {
// strings are compared case insensitive and assumed to be in the mb_internal_encoding
$cmp = strcmp(mb_strtolower($row1[$field]), mb_strtolower($row2[$field]));
} else {
$cmp = doubleval($row1[$field]) - doubleval($row2[$field]);
}
if($sort['dir'] != SORT_ASC) $cmp = -$cmp;
if($cmp != 0) return $cmp;
}
return 0;
}
usort($data,'compare');
I had the same problem. It seems that call_user_func_array() can't handle the constants.
I've solved this problem by dynamically building an argument string and evaluating this string:
$args = array($arr1, $arr2);
$order = array(SORT_ASC, SORT_DESC);
$evalstring = '';
foreach($args as $i=>$arg){
if($evalstring == ''){ $evalstring.= ', '; }
$evalstring.= '$arg';
$evalstring.= ', '.$order[$i];
}
eval("array_multisort($evalstring);");
I know eval() is evil and this is not a clean way, but it works ;-)
It is working for me :
$arrayThatNeedToSort = array('data..');
$multiSortprop = array(['data.....']=> SORT_DESC,['data.....'] => SORT_ASC)
$properties = array();
foreach ($multiSortprop as $sortArr => $sortArg) {
array_push($properties,$sortArr);
array_push($properties,$sortArg);
}
array_push($properties,$arrayThatNeedToSort);
array_multisort(...$properties);
var_dump(end($properties));

Make a router like zend

I have a url http://*.com/branch/module/view/id/1/cat/2/etc/3.
It becomes.
array
(
'module'=>'branch',
'controller'=>'module',
'action'=>'view'
);
next I need to get the params.
Ihave this array.
/*function getNextSegments($n,$segments) {
return array_slice ( $q = $this->segments, $n + 1 );
}
$params = getNextSegments(3);
*/
array ( 0 => 'id', 1 => '1', 2 => 'cat', 3 => '2', 4 => 'etc', 5 => '3' );//params
And i wanna convert it to this one:
array
(
'id'=>1,
'cat'=>2,
'etc'=>3,
);
How i can do this using php function. I know I can do using for or foreach, but I think php has such function , but i cant find it :(.
Thank you.
class A {
protected function combine($params) {
$count = count ( $params );
$returnArray = array ();
for($i = 0; $i < $count; $i += 2) {
$g = $i % 2;
if ($g == 0 or $g > 0) {
if (isset ( $params [$i] ) and isset ( $params [$i + 1] ))
$returnArray [$params [$i]] = $params [$i + 1];
}
}
return $returnArray;
}
}
This works normaly. If anybody has better logic for this please help.
Thank you again.
PHP does not have a built-in function for this. I would just implement it with explode and a loop, shouldn't be that hard.
I use a function like this in my extended Zend_Controller_Action class.
public function getCleanParams()
{
$removeElements = array(
'module' => '',
'controller' => '',
'action' => '',
'_dc' => ''
);
return array_diff_key($this->_request->getParams(), $removeElements);
}
That will give you your parameters in a clean fashion and the format you want it in.
You can start building your router with the following regular expression (name the file index.php):
<?php
$pattern = '#^(?P<module>branch)/'.
'(?P<controller>module)/'.
'(?P<action>view)'.
'(:?/id[s]?/(?P<id>[0-9]+))?'.
'(:?/cat[s]?/(?P<cat>[0-9]+))?'.
'(:?/etc[s]?/(?P<etc>[0-9]+))?#ui';
preg_match($pattern, trim($_SERVER['REQUEST_URI'], '/'), $segment);
echo sprintf('<pre>%s</pre>', var_export($segment, true));
Assuming you have PHP 5.4.x installed, you can type the following on the command-line:
% php -S localhost:8765
Now browse to http://localhost:8765/branch/module/view/id/1/cat/2/etc/3
The output will be (removed numeric keys except 0 for clarity):
array (
0 => 'branch/module/view/id/1/cat/2/etc/3',
'module' => 'branch',
'controller' => 'module',
'action' => 'view',
'id' => '1',
'cat' => '2',
'etc' => '3',
)

Parse data into array

I'm creating a "quote database" for a TV show I'm a fan of, and I'm rewriting parts of it I don't particularly like. I came across my function to parse the data holding the quote and characters into an array that I can easily loop through and display. One of the features of the site is that you can have a single quote (one-liner) or a conversation between several characters. Right now I'm storing single quotes like this:
[charactername]This is my witty one-liner.
And conversations follow the same pattern:
[characternameone]How's the weather?
[characternametwo]Pretty good, actually.
And so on. Here's the aforementioned parsing function:
function parse_quote($text)
{
// Determine if it's a single or convo
if ( strpos($text, "\n") != false )
{
// Convo
// Let's explode into the separate characters/lines
$text = explode("\n", $text);
$convo = array();
// Parse each line into character and line
foreach ( $text as $part )
{
$character = substr($part, 1, strpos($part, ']') - 1);
$line = substr($part, strlen($character) + 2);
$convo[] = array(
'character' => $character,
'line' => $line
);
}
return array(
'type' => 'convo',
'quote' => $convo
);
}
else
{
// Single
// Parse line into character and line
return array(
'type' => 'single',
'quote' => array(
'character' => substr($text, 1, strpos($text, ']') - 1),
'line' => substr($text, strlen(substr($text, 1, strpos($text, ']') - 1)) + 2)
)
);
}
}
It works as expected, but I can't help but think there's a better way to do this. I'm horrible with regular expressions, which I assume would come in at least somewhat handy in this situation. Any advice, or improvements?
Personally, I would change your data storage method. It would be much easier to deal with a serialized or JSON encoded string.
Instead of
[characternameone]How's the weather?
[characternametwo]Pretty good, actually.
you would have
array(
[0] => {
'name' => "characternameone",
'quote' => "How's the weather?"
},
[1] => {
'name' => "characternametwo",
'quote' => "Pretty good, actually"
}
)
Then when you read it out, there isn't any parsing.
function display_quote($input)
{
for ($i=0, $n=count($input); $i<$n; $i++) {
$quote = $input[$i];
if ( $i > 0 ) echo "\n";
echo $quote['name'] . ': ' . $quote['quote'];
}
}
Instead of
$character = substr($part, 1, strpos($part, ']') - 1);
$line = substr($part, strlen($character) + 2);
$convo[] = array(
'character' => $character,
'line' => $line
);
you could try
preg_match('#\[([^\]]+)\](.*)#ism', $part, $match);
$convo[] = array(
'character' => $match[1],
'line' => $match[2]
);
HTH

Categories