I am new to php but learning fast. I am trying to extract the lowest price from a string of values like -
"12/6/2020:Some Text:345.44,13/6/2020:Some Text:375.88,14/6/2020:Some Text:275.81"
I need to get the value just before each comma and then get the lowest of these values. I know I can use min() if I get these values in a string. For the above example I need 275.81 (lowest).
Please see my code below. I am trying to explode the values and then put in a string. I dont think this is the best way by far and not having any luck. is there a better/cleaner way to do this?
$dates = explode(',', $resultx);
foreach($dates as $datew) {
$dater = explode(':', $datew);
echo $dater[2]. ",";
}
You can use regular expressions to extract the values, and then use min() to get the minimum value
<?php
$input = "2/6/2020:Some Text:345.44,13/6/2020:Some Text:375.88,14/6/2020:Some Text:275.81";
$pattern = '/(?:[^\:]+)\:(?:[^\:]+)\:(\d+\.\d+)\,*/';
if (preg_match_all($pattern, $input, $matches)) {
$minimumValue = min($matches[1]);
echo "minimum is: " . $minimumValue;
}
Here is a working example on 3v4l.org
In the pattern (?:[^\:]+) - equals any symbol, except the colon :
Section (\d+\.\d+) says that we need to capture the sequence containing two numbers with a dot . between them.
We look for two sections with any symbols, except :, and then capturing the third sections containing numbers, and everything ends with an optional comma ,
P.S. you could still get the result with your current approach
<?php
$input = "2/6/2020:Some Text:345.44,13/6/2020:Some Text:375.88,14/6/2020:Some Text:275.81";
$minimumValue = null;
$dates = explode(',', $input);
foreach($dates as $datew) {
$dater = explode(':', $datew);
$currentValue = floatval($dater[2]);
if (is_null($minimumValue) || $minimumValue > $currentValue) {
$minimumValue = $currentValue;
}
}
echo $minimumValue;
Here is a link to your approach on 3v4l.org
Related
I have an array with rule field that has a string like this:
FREQ=MONTHLY;BYDAY=3FR
FREQ=MONTHLY;BYDAY=3SA
FREQ=WEEKLY;UNTIL=20170728T080000Z;BYDAY=MO,TU,WE,TH,FR
FREQ=MONTHLY;UNTIL=20170527T100000Z;BYDAY=4SA
FREQ=WEEKLY;BYDAY=SA
FREQ=WEEKLY;INTERVAL=2;BYDAY=TH
FREQ=WEEKLY;BYDAY=TH
FREQ=WEEKLY;UNTIL=20170610T085959Z;BYDAY=SA
FREQ=MONTHLY;BYDAY=2TH
Each line is a different array, I am giving a few clues to get an idea of what I need.
What I need is to write a regex that would take off all unnecessary values.
So, I don't need FREQ= ; BYDAY= etc. I basically need the values after = but each one I want to store in a different variable.
Taking third one as an example it would be:
$frequency = WEEKLY
$until = 20170728T080000Z
$day = MO, TU, WE, TH, FR
It doesn't have to be necessarily one regex, there can be one regex for each value. So I have one for FREQ:
preg_match("/[^FREQ=][A-Z]+/", $input_line, $output_array);
But I can't do it for the rest unfortunately, how can I solve this?
The only way to go would be PHP array destructuring:
$str = "FREQ=WEEKLY;UNTIL=20170728T080000Z;BYDAY=MO,TU,WE,TH,FR";
preg_match_all('~(\w+)=([^;]+)~', $str, $matches);
[$freq, $until, $byday] = $matches[2]; // As of PHP 7.1 (otherwise use list() function)
echo $freq, " ", $until, " ", $byday;
// WEEKLY 20170728T080000Z MO,TU,WE,TH,FR
Live demo
Be more general
Using extract function:
preg_match_all('~(\w+)=([^;]+)~', $str, $m);
$m[1] = array_map('strtolower', $m[1]);
$vars = array_combine($m[1], $m[2]);
extract($vars);
echo $freq, " ", $until, " ", $byday;
Live demo
Notice: For this problem, I recommend the generell approach #revo posted, it's concise and safe and easy on the eyes -- but keep in mind, that regular expressions come with a performance penalty compared to fixed string functions, so if you can use strpos/substr/explode/..., try to use them, don't 'knee-jerk' to a preg_-based solution.
Since the seperators are fixed and don't seem to occur in the values your are interested in, and you furthermore rely on knowledge of the keys (FREQ:, etc) you don't need regular-expressions (as much as I like to use them anywhere I can, and you can use them here); why not simply explode and split in this case?
$lines = explode("\n", $text);
foreach($lines as $line) {
$parts = explode(';', $line);
$frequency = $until = $day = $interval = null;
foreach($parts as $part) {
list($key, $value) = explode('=', $part);
switch($key) {
case 'FREQ':
$frequency = $value;
break;
case 'INTERVAL':
$interval = $value;
break;
// and so on
}
}
doSomethingWithTheValues();
}
This may be more readable and efficient if your use-case is as simple as stated.
You need to use the Pattern
;?[A-Z]+=
together with preg_split();
preg_split('/;?[A-Z]+=/', $str);
Explanation
; match Semikolon
? no or one of the last Character
[A-Z]+ match one or more uppercase Letters
= match one =
If you want to have each Line into a seperate Array, you should do it this Way:
# split each Line into an Array-Element
$lines = preg_split('/[\n\r]+/', $str);
# initiate Array for Results
$results = array();
# start Looping trough Lines
foreach($lines as $line){
# split each Line by the Regex mentioned above and
# put the resulting Array into the Results-Array
$results[] = preg_split('/;?[A-Z]+=/', $line);
}
Suppose I have a string:
$str="1,3,6,4,0,5";
Now user inputs 3.
I want that to remove 3 from the above string such that above string should become:
$str_mod="1,6,4,0,5";
Is there any function to do the above?
You can split it up, remove the one you want then whack it back together:
$str = "1,3,6,4,0,5";
$userInput = 3;
$bits = explode(',', $str);
$result = array_diff($bits, array($userInput));
echo implode(',', $result); // 1,6,4,0,5
Bonus: Make $userInput an array at the definition to take multiple values out.
preg_replace('/\d[\D*]/','','1,2,3,4,5,6');
in place of \d just place your digit php
If you don't want to do string manipulations, you can split the string into multiple pieces, remove the ones you don't need, and join the components back:
$numberToDelete = 3;
$arr = explode(',',$string);
while(($idx = array_search($numberToDelete, $components)) !== false) {
unset($components[$idx]);
}
$string = implode(',', $components);
The above code will remove all occurrences of 3, if you want only the first one yo be removed you can replace the while by an if.
I have an array with strings like:
209#ext-local : SIP/209 State:Idle Watchers 2
208#ext-local : SIP/208 State:Unavailable Watchers 1
How can I echo the state for example Idle or Unavailable?
Thanks.
Using regex it will match any string containing letters and numbers.
$string = '209#ext-local : SIP/209 State:Idle Watchers 2';
preg_match("/State\:([A-Za-z0-9]+)/", $string, $results);
echo $results[1]; // Idle
strpos will search the string to see if it is contains the characters in that exact order.
strpos will not always work if the word idle or unavailable has the possibility to show up in any other way in the string.
You can use the php explode and parse the sting into an array of strings.
exp.
$string = "209#ext-local : SIP/209 State:Idle Watchers 2";
$string = explode(':', $string);
will give you ['209#ext-local ',' SIP/209 State','Idle Watchers 2']. Then if you explode the 3rd entry my ' ' you would get your answer.
$answer = explide(' ', $string[2]);
echo $answer[0];
Assuming your strings are all the same format, you can try splitting the string down using explode(), which returns an array of string, separated by a provided delimiter, like
foreach ($yourStrings as $s) {
$colonSplit = explode(":", $stringToSplit);
$nextStringToSplit = $colonSplit[2];
$spaceSplit = explode(" ", $nextStringToSplit);
$status = $spaceSplit[0];
echo $status;
}
May not be elegant but it should work.
Quick (and dirty) way. Assuming your array contains the full elements you listed above, the array element values do NOT contain 'idle' or 'unavailable' in any other capacity other than what you listed, and you just want to echo out the value and "is idle" or "is unavailable":
//$a being your array containing the values you listed above
foreach ($a as $status) {
if (strpos($status, "Idle") == true)
echo $status . " is idle";
elseif (strpos($status, "Unavailable") == true)
echo "$status" . " is unavailable";
}
I want to get sentence(s) which include(s) searched word(s). I have tried this but can't make it work properly.
$string = "I think instead of trying to find sentences, I'd think about the amount of
context around the search term I would need in words. Then go backwards some fraction of this number of words (or to the beginning) and forward the remaining number
of words to select the rest of the context.";
$searchlocation = "fraction";
$offset = stripos( strrev(substr($string, $searchlocation)), '. ');
$startloc = $searchlocation - $offset;
echo $startloc;
You can get all sentences.
try this:
$string = "I think instead of trying to find sentences, I'd think about the amount of
context around the search term I would need in words. Then go backwards some fraction of this number of words (or to the beginning) and forward the remaining number
of words to select the rest of the context.";
$searchlocation = "fraction";
$sentences = explode('.', $string);
$matched = array();
foreach($sentences as $sentence){
$offset = stripos($sentence, $searchlocation);
if($offset){ $matched[] = $sentence; }
}
var_export($matched);
using array_filter function
$sentences = explode('.', $string);
$result = array_filter(
$sentences,
create_function('$x', "return strpos(\$x, '$searchlocation');"));
Note: the double quote in the second parameter of create_function is necessary.
If you have anonymous function support, you can use this,
$result = array_filter($sentences, function($x) use($searchlocation){
return strpos($x, $searchlocation)!==false;
});
Since you reverse the string with strrev(), you will find [space]. instead of .[space].
I'm using
$regex = '/'.implode('|', 10).'/i';
preg_match($regex, $ids)
to find the number 10 in a list of IDs ($ids). However, if the list of IDs looks like this:
$ids = array(10, 110, 1010);
Would it bring back all of them? How can I make it find the exact number I am after, and not just find a number that contains the number I'm after?
Thanks.
Edit:
I made a mistake above. The list of IDs is actually a string of comma separated values. For example:
$ids = "10,1010,101";
It's hard to explain the whole idea process behind this, but this is my full code:
<?php
$file = fopen('allprods.csv', 'r');
$id = array($_GET['id']);
$id = array_map('preg_quote', $id);
$regex = '/'.implode('|', $id).'/i';
$skus = array();
while (($line = fgetcsv($file)) !== FALSE) {
list($ids, $sku) = $line;
if(preg_match($regex, $ids)) {
$skus[] = $sku;
}
}
$count = count($skus);
$i = 1;
echo $category_id;
foreach ($skus as $sku){
echo $sku;
if($i != $count) { echo "`"; }
$i++;
}
I'm essentially rooting through a csv that has an ID column (some rows have multiple ids in that column, spearated by commas), and an sku column. More info here
So I need the code to check the string of ids for a certain ID, for example 10, and then add the appropriate SKU to an sku array.
I'm sure this code is a mess, so bear with me while I hack PHP to bits!
Edit: This is now solved! I used in_array instead, as mentioned in the answers. First of all I exploded the comma separate string. Code can be seen below:
$skus = array();
while (($line = fgetcsv($file)) !== FALSE) {
list($ids, $sku) = $line;
$cats = explode(',',$ids);
if (in_array($_GET['id'], $cats)) {
$skus[] = $sku;
}
}
Thanks for the help all.
Don't use a regex for this. Use in_array()
if( in_array(10, $ids) ) {
// do something
}
else {
// not found
}
In regex, if you want to find an exact match rather than just a substring match, you need to use start and end anchors. These are represented in regex by the ^ (start) and $ (end) characters.
So your regex to find "10" and not "110", etc, would be /^10$/.
But if you're looking for a number, why not just use == or in_array()?
PHP is quite capable of evaluating a numeric without having to parse it with regular expressions.
$regex = '/^10$/';
this will only match if the ^ is the beginning of the string, and the $ is the end of the string.
I'd use in_array() as suggested by #Cfreak, but if you want to use regex to match an id of 10 you can do
preg_match('/[^\d]?10[^\d]?/', implode('|', $ids))
If you have array(1,10,1010,010), implode() will change this to 1|10|1010|010 and the pattern will match against '10' not preceded or followed by any other digit (ie. another 0 or 1 as in 0101)