Search elements inside string - php

Let me explain what I want to do.
I need to connect to a device using SSH and execute some shell commands. I get the result of these commands (stream, using ssh2_fetch_stream) and save into a variable. This Works fine.
But what I need to know is how can I search by elements in a string?
Here a sample string:
$stringToSearch = "id=10 name=interfacename1 stringx=102040 stringy=50606040,id=20 name=interfacename2 stringx=872345 stringy=23875454,id=30 name=interfacename3 stringx=654389 stringy=34567865";
I need to obtain all the 'name=' results, like (SELECT name FROM stringToSearch;) and this would return:
____name____
interfacename1
interfacename2
interfacename3
I created a simple function to read this string.
<?php
function readString($stringToSearch, $start, $end) {
$result = '-1';
// I need to do a loop here, but how can I do it to read and return all elements between $start and $end?
if(strlen(strstr($stringToSearch, $start)) > 0)
{
$startsAt = strpos($stringToSearch, $start) + strlen($start);
$endsAt = strpos($stringToSearch, $end, $startsAt);
$result = substr($stringToSearch, $startsAt, $endsAt - $startsAt);
}
return $result;
}
$stringToSearch = 'id=10 name=interfacename1 stringx=102040 stringy=50606040,id=20 name=interfacename2 stringx=872345 stringy=23875454,id=30 name=interfacename3 stringx=654389 stringy=34567865';
$element = readString($stringToSearch, 'name=', ' '); // Will return only the 1st element
?>
But I can only retrieve the 1st element. How can I get all the elements in this string?

try with this solution :)
<?php
$stringToSearch = "id=10 name=interfacename1 stringx=102040 stringy=50606040,id=20 name=interfacename2 stringx=872345 stringy=23875454,id=30 name=interfacename3 stringx=654389 stringy=34567865";
var_dump(getName($stringToSearch));
function getName($stringToSearch) {
$pattern = '/name=([A-Z0-9]*)/i';
if(preg_match_all($pattern, $stringToSearch, $result) == 0){
return NULL;
}
return $result[1];
}
Enhancement (to get all values of desired parameter):
/**
* #param String $varName : the name of variable to get their values. ex: stringx, stringy
* #param String $stringToSearch : the string to search in
* #return Array if variable was found in $stringToSearch, NULL else
*/
function getName($varName, $stringToSearch) {
$pattern = '/' . $varName . '=([A-Z0-9]*)/i';
if(preg_match_all($pattern, $stringToSearch, $result) == 0){
return NULL;
}
return $result[1];
}

Using Halayem Anis's answer I was able to find all the elements in the string.
But I found other problem. If I have a string like that: name="foo bar" (with space at the middle).
To solve this problem I adapted the $pattern.
The result is:
//$varname = string to be searched like name=
//$stringToSearch = the original string
function getName($varName, $stringToSearch) {
$pattern = '/(?<=' . $varName . ')"(.*?)"/i'; // Changed this to get all between name=""
if(preg_match_all($pattern, $stringToSearch, $result) == 0){
return NULL;
}
return $result[1];
}

Related

Replace certain characters in a string from array values

I've got an array :
$arr = [5, "David"];
I've got a query :
$query = "SELECT * FROM users WHERE user_id = ? AND user_name = ?";
I want to create a logger query that takes these 2 and returns the query, manually.
logger($query, $arr); // returns : SELECT * FROM users WHERE user_id = 5 AND user_name = 'David'
I'm using eloquent's capsule manager.
I tried doing something like this but it doesn't replace anything :
function logger($query, $arr) {
foreach($arr as $a) {
is_numeric($a) ? str_replace("?",$a,$query) : str_replace("?","'".$a."'",$query);
}
return $query;
}
Why isn't this code working?
str_replace does not modify its argument, it returns the modified value instead. So you need to assign its output to a variable. However the problem is that str_replace will replace all occurrences of the pattern at the same time. Instead, you can use preg_replace, which has a limit parameter which can be used to tell it to replace only one occurrence of the pattern for each call. I've used a pattern for preg_replace that will ensure that only a ? on its own in the query will be replaced, in case there is a question mark elsewhere e.g. in a column alias. Change your function to this:
function logger($query, $arr) {
foreach($arr as $a) {
$query = is_numeric($a) ?
preg_replace("/(?<=\s)\?(?=\s|$)/", $a, $query, 1) :
preg_replace("/(?<=\s)\?(?=\s|$)/", "'$a'", $query, 1);
}
return $query;
}
Output:
SELECT * FROM users WHERE user_id = 5 AND user_name = 'David'
Demo on 3v4l.org
I found out how to do it, by using str_replace_first and assiging the value into a variable.
foreach($params as $a) {
$query = is_numeric($a) ? str_replace_first("?",$a,$query,1) : str_replace_first("?","'".$a."'",$query);
}
return $query;
str_replace_first :
function str_replace_first($search_for, $replace_with, $in) {
$pos = strpos($in, $search_for);
if($pos === false) {
return $in;
} else {
return substr($in, 0, $pos) . $replace_with . substr($in, $pos + strlen($search_for), strlen($in));
}
}

Creating a function that takes arguments and passes variables

I am creating a script that will locate a field in a text file and get the value that I need.
First used the file() function to load my txt into an array by line.
Then I use explode() to create an array for the strings on a selected line.
I assign labels to the array's to describe a $Key and a $Value.
$line = file($myFile);
$arg = 3
$c = explode(" ", $line[$arg]);
$key = strtolower($c[0]);
if (strpos($c[2], '~') !== false) {
$val = str_replace('~', '.', $c[2]);
}else{
$val = $c[2];
}
This works fine but that is a lot of code to have to do over and over again for everything I want to get out of the txt file. So I wanted to create a function that I could call with an argument that would return the value of $key and $val. And this is where I am failing:
<?php
/**
* #author Jason Moore
* #copyright 2014
*/
global $line;
$key = '';
$val = '';
$myFile = "player.txt";
$line = file($myFile); //file in to an array
$arg = 3;
$Character_Name = 3
function get_plr_data2($arg){
global $key;
global $val;
$c = explode(" ", $line[$arg]);
$key = strtolower($c[0]);
if (strpos($c[2], '~') !== false) {
$val = str_replace('~', '.', $c[2]);
}else{
$val = $c[2];
}
return;
}
get_plr_data2($Character_Name);
echo "This character's ",$key,' is ',$val;
?>
I thought that I covered the scope with setting the values in the main and then setting them a global within the function. I feel like I am close but I am just missing something.
I feel like there should be something like return $key,$val; but that doesn't work. I could return an Array but then I would end up typing just as much code to the the info out of the array.
I am missing something with the function and the function argument to. I would like to pass and argument example : get_plr_data2($Character_Name); the argument identifies the line that we are getting the data from.
Any help with this would be more than appreciated.
::Updated::
Thanks to the answers I got past passing the Array.
But my problem is depending on the arguments I put in get_plr_data2($arg) the number of values differ.
I figured that I could just set the Max of num values I could get but this doesn't work at all of course because I end up with undefined offsets instead.
$a = $cdata[0];$b = $cdata[1];$c = $cdata[2];
$d = $cdata[3];$e = $cdata[4];$f = $cdata[5];
$g = $cdata[6];$h = $cdata[7];$i = $cdata[8];
$j = $cdata[9];$k = $cdata[10];$l = $cdata[11];
return array($a,$b,$c,$d,$e,$f,$g,$h,$i,$j,$k,$l);
Now I am thinking that I can use the count function myCount = count($c); to either amend or add more values creating the offsets I need. Or a better option is if there was a way I could generate the return array(), so that it would could the number of values given for array and return all the values needed. I think that maybe I am just making this a whole lot more difficult than it is.
Thanks again for all the help and suggestions
function get_plr_data2($arg){
$myFile = "player.txt";
$line = file($myFile); //file in to an array
$c = explode(" ", $line[$arg]);
$key = strtolower($c[0]);
if (strpos($c[2], '~') !== false) {
$val = str_replace('~', '.', $c[2]);
}else{
$val = $c[2];
}
return array($key,$val);
}
Using:
list($key,$val) = get_plr_data2(SOME_ARG);
you can do this in 2 way
you can return both values in an array
function get_plr_data2($arg){
/* do what you have to do */
$output=array();
$output['key'] =$key;
$output['value']= $value;
return $output;
}
and use the array in your main function
you can use reference so that you can return multiple values
function get_plr_data2($arg,&$key,&$val){
/* do job */
}
//use the function as
$key='';
$val='';
get_plr_data2($arg,$key,$val);
what ever you do to $key in function it will affect the main functions $key
I was over thinking it. Thanks for all they help guys. this is what I finally came up with thanks to your guidance:
<?php
$ch_file = "Thor";
$ch_name = 3;
$ch_lvl = 4;
$ch_clss = 15;
list($a,$b)= get_char($ch_file,$ch_name);//
Echo $a,': ',$b; // Out Puts values from the $cdata array.
function get_char($file,$data){
$myFile = $file.".txt";
$line = file($myFile);
$cdata = preg_split('/\s+/', trim($line[$data]));
return $cdata;
}
Brand new to this community, thanks for all the patience.

search for a substring which returns true if it is at the end

I would like to search for a substring in php so that it will be at the end of the given string.
Eg
on string 'abd def' if I search for def it would be at the end, so return true. But if I search for abd it will return false since it is not at the end.
Is it possible?
You could use preg_match for this:
$str = 'abd def';
$result = (preg_match("/def$/", $str) === 1);
var_dump($result);
An alternative way to do it which does not require splitting by a separator or regular expressions. This tests whether the last x characters equal the test string, where x equals the length of the test string:
$string = "abcdef";
$test = "def";
if(substr($string, -(strlen($test))) === $test)
{
/* logic here */
}
Assuming whole words:
$match = 'def';
$words = explode(' ', 'abd def');
if (array_pop($words) == $match) {
...
}
Or using a regex:
if (preg_match('/def$/', 'abd def')) {
...
}
This answer should be fully robust regardless of full words or anything else
$match = 'def';
$words = 'abd def';
$location = strrpos($words, $match); // Find the rightmost location of $match
$matchlength = strlen($match); // How long is $match
/* If the rightmost location + the length of what's being matched
* is equal to the length of what's being searched,
* then it's at the end of the string
*/
if ($location + $matchlength == strlen($words)) {
...
}
Please look strrchr() function. Try like this
$word = 'abcdef';
$niddle = 'def';
if (strrchr($word, $niddle) == $niddle) {
echo 'true';
} else {
echo 'false';
}

Reusing PHP function for accessing an array item tag from XML document

I have created a website that contains that uses XML to drive some of its contents, for example, the current exchange rates as shown below.
The website compares three exchange rates and I currently use a separate functions for each city that perform identical goals e.g. returning the current exchange rates.
The only difference between these functions are the positions of the item tag from the XML document that I request the data from.
$exchange['rate'] = $xml->channel->item[15]->description;
Notice item[15] in the above array which provides access to the Euro currency. In the following, the USA currency is item[56] as below.
$exchange['rate'] = $xml->channel->item[56]->description;
Any ideas if it is possible to combine the three functions into a single one to increase cohesion?
The function I use for accessing the Euro currency is:
<?php
function get_rate1(SimpleXMLElement $xml) {
// Match numeric values before and after decimal place
$exchange['rate'] = $xml->channel->item[15]->description;
preg_match('/([0-9]+\.[0-9]+)/', $exchange['rate'], $matches);
$rate = $matches[0];
// Get currency type from title
$title['rate'] = $xml->channel->item[15]->title;
$title = explode('/', $title['rate']);
$title = $title[0];
echo $rate . ' ' . $title . '<br />';
return $rate;
}
?>
The feed URL's are set in another configuration script called cityConfig.php
<?php
// City 1 //
$city1 = 'Paris';
$exchangeRate1 = '1 Euro';
$exchangeRate1RssUrl = 'http://themoneyconverter.com/rss-feed/EUR/rss.xml';
?>
Thanks in advance
Try this on for size - it uses the three letter currency codes, and uses XPath to find them, doing away with those nasty indexes altogether. All you need to supply is the three letter code of the source currency, and the three letter code of the destination, or an array of destinations if you want to get more than one at once.
MODIFIED so that $dest is now optional. If only $source is supplied, return an array of all exchange rates.
function get_rate ($source, $dest = NULL) {
// Make sure source currency is upper case
$source = strtoupper($source);
// Construct the source URL
$url = "http://themoneyconverter.com/rss-feed/$source/rss.xml";
// This will hold the results
$result = array();
// Fetch and parse the data
if (!$xml = simplexml_load_file($url)) {
return FALSE;
}
if ($dest === NULL) {
// Get all <item> nodes and loop them
foreach ($xml->xpath("//item") as $item) {
// Find the code of this currency
$currencyParts = explode('/', $item->title);
// Get the value of this currency
$result[$currencyParts[0]] = (preg_match('/([0-9]+\.[0-9]+)/', $item->description, $matches)) ? (float) $matches[0] : FALSE;
}
} else {
// Loop the destination currencies
foreach ((array) $dest as $currency) {
// Make sure destination currencies are upper case
$currency = strtoupper($currency);
// Perform an XPath search for this currency
$nodes = $xml->xpath("//item[title='$currency/$source']/description");
// If we found the currency and could extract the value, add it to the
// result array as a float
$result[$currency] = (count($nodes) === 1 && preg_match('/([0-9]+\.[0-9]+)/', $nodes[0], $matches)) ? (float) $matches[0] : FALSE;
}
}
// If only a single value was requested return it, otherwise return the array
return (count($result) === 1) ? array_shift($result) : $result;
}
Example usage:
$result = get_rate('GBP', 'USD');
var_dump($result);
/*
float(1.58014)
*/
$result = get_rate('GBP', array('USD', 'EUR'));
var_dump($result);
/*
array(2) {
["USD"]=>
float(1.58014)
["EUR"]=>
float(1.20236)
}
*/
$result = get_rate('GBP');
var_dump($result);
/*
array(64) {
["AED"]=>
float(5.80445)
["ARS"]=>
float(6.85316)
["AUD"]=>
float(1.47589)
["BBD"]=>
float(3.16103)
["BHD"]=>
float(0.59427)
["BOB"]=>
float(10.92135)
["BRL"]=>
float(2.72171)
["CAD"]=>
float(1.57968)
["CHF"]=>
float(1.44883)
["CLP"]=>
float(759.35947)
["CNY"]=>
float(9.96753)
["COP"]=>
float(2840.97943)
["CZK"]=>
float(30.15863)
["DKK"]=>
float(8.97219)
["EGP"]=>
float(9.53446)
["EUR"]=>
float(1.20265)
["HKD"]=>
float(12.24901)
["HUF"]=>
float(350.91425)
["IDR"]=>
float(14121.92063)
["ILS"]=>
float(5.87877)
["INR"]=>
float(77.48491)
["ISK"]=>
float(194.46687)
["JMD"]=>
float(136.31954)
["JOD"]=>
float(1.12059)
["JPY"]=>
float(120.36272)
["KES"]=>
float(132.28924)
["KRW"]=>
float(1763.3828)
["KWD"]=>
float(0.43897)
["LBP"]=>
float(2382.62959)
["LKR"]=>
float(180.02093)
["LTL"]=>
float(4.1525)
["LVL"]=>
float(0.84522)
["MAD"]=>
float(13.39206)
["MXN"]=>
float(20.24582)
["MYR"]=>
float(4.77078)
["NAD"]=>
float(12.10631)
["NGN"]=>
float(253.27781)
["NOK"]=>
float(9.21948)
["NPR"]=>
float(123.97585)
["NZD"]=>
float(1.89597)
["OMR"]=>
float(0.6077)
["PAB"]=>
float(1.58052)
["PEN"]=>
float(4.25316)
["PHP"]=>
float(67.48803)
["PKR"]=>
float(142.95779)
["PLN"]=>
float(5.03909)
["QAR"]=>
float(5.75308)
["RON"]=>
float(5.23271)
["RUB"]=>
float(47.73085)
["SAR"]=>
float(5.92694)
["SEK"]=>
float(10.66422)
["SGD"]=>
float(1.96993)
["THB"]=>
float(48.79218)
["TRY"]=>
float(2.77931)
["TWD"]=>
float(46.6742)
["UAH"]=>
float(12.71293)
["USD"]=>
float(1.58052)
["UYU"]=>
float(30.74107)
["VEF"]=>
float(6.79622)
["VND"]=>
float(33119.73602)
["XAF"]=>
float(788.88394)
["XCD"]=>
float(4.2674)
["XOF"]=>
float(788.88394)
["ZAR"]=>
float(12.10631)
}
*/
How about you change the rate function to this:
<?php
function get_rate(SimpleXMLElement $xml, $id) {
// Match numeric values before and after decimal place
$exchange['rate'] = $xml->channel->item[$id]->description;
preg_match('/([0-9]+\.[0-9]+)/', $exchange['rate'], $matches);
$rate = $matches[0];
// Get currency type from title
$title['rate'] = $xml->channel->item[$id]->title;
$title = explode('/', $title['rate']);
$title = $title[0];
echo $rate . ' ' . $title . '<br />';
return $rate;
}
?>
Then you can call it like this instead:
$rate1 = get_rate($xml,15);
$rate2 = get_rate($xml,56);
Since I can't comment yet...helk's answer is perfect - you could take it one step further and define some class constants or define()'d constants so you aren't dealing with hard to remember numbers in your code (remember, you may not be the only person who ever looks at this code - you know what 15 is, but Jr. Dev Newguy does not):
<?php
define('CURRENCY_USA', 56);
define('CURRENCY_EURO', 15);
// OR something like:
class CurrencyHelper
{
const CURRENCY_USA = 56;
const CURRENCY_EURO = 15;
// of course, you could also define get_rate here too...
public function __construct(SimpleXmlElement $xml)
{
$this->xml = $xml;
}
public function get_rate($id)
{
// ... your code here
}
}
// Or, define your get_rate as originally intended:
function get_rate(SimpleXMLElement $xml, $id) {
// Match numeric values before and after decimal place
$exchange['rate'] = $xml->channel->item[$id]->description;
preg_match('/([0-9]+\.[0-9]+)/', $exchange['rate'], $matches);
$rate = $matches[0];
// Get currency type from title
$title['rate'] = $xml->channel->item[$id]->title;
$title = explode('/', $title['rate']);
$title = $title[0];
echo $rate . ' ' . $title . '<br />';
return $rate;
}
// Finally:
echo get_rate($xml, CURRENCY_EURO); // define
echo get_rate($xml, CurrencyHelper::CURRENCY_USA; // class constant
$myCurr = new CurrencyHelper($xml);
$myCurr->get_rate(CurrencyHelper::CURRENCY_USA); // Over-oop'd solution : P
?>

String to array without explode

I am using an api to retrieve data from another server the data returned is something like this:
accountid=10110 type=prem servertime=1263752255 validuntil=1266163393
username= curfiles=11 curspace=188374868 bodkb=5000000 premkbleft=24875313
This is a whole string I need two values out of whole string, I am currently using preg_match to get it, but just to learn more and improve my coding is there any other way or function in which all values are automatically convert to array?
Thank You.
Sooo, my faster-than-preg_split, strpos-based function looks like this:
function unpack_server_data($serverData)
{
$output = array();
$keyStart = 0;
$keepParsing = true;
do
{
$keyEnd = strpos($serverData, '=', $keyStart);
$valueStart = $keyEnd + 1;
$valueEnd = strpos($serverData, ' ', $valueStart);
if($valueEnd === false)
{
$valueEnd = strlen($serverData);
$keepParsing = false;
}
$key = substr($serverData, $keyStart, $keyEnd - $keyStart);
$value = substr($serverData, $valueStart, $valueEnd - $valueStart);
$output[$key] = $value;
$keyStart = $valueEnd + 1;
}
while($keepParsing);
return $output;
}
It looks for an equals character, then looks for a space character, and uses these two to decide where a key name begins, and when a value name begins.
Using explode is the fastest for this, no matter what.
However, to answer you question, you can do this many ways. But just because you can, doesn't mean you should. But if you really wanna make it weird, try this.
UPdated using strpos
$arr = array();
$begin = 0;
$str = trim($str); # remove leading and trailing whitespace
while ($end = strpos($str, ' ', $begin)) {
$split = strpos($str, '=', $begin);
if ($split > $end) break;
$arr[substr($str, $begin, $split-$begin)] = substr($str, $split+1, $end-$split-1);
$begin = $end+1;
}
try out parse_str maybe you need to do str_replace(' ', '&', $string); before

Categories