I want to check all elements of an array and find out, whether at least one of them is prefixed by a given string:
public function validateStringByPrefix(string $string, $prefix)
{
$valid = false;
if (is_string($prefix)) {
if (strpos($string, $prefix) === 0) {
$valid = true;
}
} elseif (is_array($prefix)) {
foreach ($prefix as $partPrefix) {
if (strpos($string, $partPrefix) === 0) {
$valid = true;
break;
}
}
}
return $valid;
}
Is it possible / How to to achieve the same a more efficient way?
(It's a cheap method, but it's called a lot of times in my application, so even a minimal improvement might appreciably increase the application's performance.)
You can try next solution:
public function validateStringByPrefix(string $string, $prefix)
{
return (bool)array_filter((array)$prefix, function($prefix) use ($string) {
return strpos($string, $prefix)===0;
});
}
P.S. In case you have few large arrays (with prefixes), my solution is less efficient and you can combine our approaches like this:
public function validateStringByPrefix(string $string, $prefix)
{
if($string=='') {
return false;
}
foreach ((array)$prefix AS $subprefix) {
if (strpos($string, $subprefix)===0) {
return true;
}
}
return false;
}
There are many ways to rome....
//your array to test for
$array=[];
//set valid to false
$valid=false;
//setup prefixes array or not
$prefix='whatever';
//make array if you dont have one
!is_array($prefix) AND $prefix=array($prefix);
//prepare for use as REGEX
$prefix=implode('|',$prefix);
//do the work
array_walk($array,function($val,$key) use(&$valid,$prefix){
if (!$valid && preg_match("#^($prefix)#",$key)) {
$valid = true;
}
});
var_export($valid);
I used preg_match here, because $prefix can be an array, so the math would be: n+ strpos() calls vs. one preg_match() call
And after a single item matches, no more preg_match are called, just iteration to the end and out.
Related
I'm trying to check for if a string contains any blacklisted words from an array of string.
This is my current code - the focus is efficiency, string from list may be empty, the string we search in is never empty:
public static function includes_from_array($stringArray, $searchInMe, $offset=0) : bool {
// if not array just check if $stringArray exists in our $searchInMe string.
if(!is_array($stringArray)) {
return strpos($stringArray, $searchInMe) !== false;
}
foreach($stringArray as $query) {
if ($query === '') {
continue;
}
else if(strpos($searchInMe, strtolower($query), $offset) !== false) {
return true;
}
}
return false;
}
Is there a way to shorten the code quickly without harming efficiency or even improving it?
The code was written as it is currently to be able to retrieve the position if required (changing from true or false to pos returned in check), however it is not required in the shortened version.
Thanks!
As per my understanding you soul purpose is to check any bad word is present in sentence or URL and if present then return Boolean true.
Kindly try like this:
<?php
function includes_from_array($stringArray, $searchInMe){
if(is_array($stringArray)){
foreach($stringArray as $arr){
if(strpos($searchInMe,$arr) !== false){
return true;
}
}
}else{
if(strpos($searchInMe,$stringArray) !== false){
return true;
}
}
return false;
}
Sample Output : https://3v4l.org/3Pefn
I am using 2 regex functions here and I wanna make another function which returns false when the 2 regex are both false and if not, then true.
The problem here is when I wanna use the 2 regex functions in the third one, I have to give them parameters, which is not necessary I think, because the third function will only return a simple true or false. I get an undefined variable whenever I give parameters to the 2 regex functions in the 3rd one.
I tried using global variables which works but since its a bad practice I am looking for a better solution.
Code:
function regex1($input)
{
$regex= "/^[A-Za-z0-9 ]*$/";
if (!preg_match($regex, $input))
{
return false;
}
else
{
return true;
}
}
function regex2($input)
{
$regex= "/^[A-Za-z0-9 ]*$/";
if (!preg_match($regex, $input))
{
return false;
}
else
{
return true;
}
}
function checkBoth()
{
if (regex1($input) === false || regex2($input) === false)
{
return false;
}
else
{
return true;
}
}
EDIT:
The checkBoth function I am using in my other file like this together with the other 2 regex functions:
if (!regex1($input))
{
// show error at the same time
}
if (!regex2($input))
{
// show error at the same time
}
if(checkBoth())
{
// success
}
function regex2($input,$secondVar=false)
{....
Later in code in place where you need just add:
if($secondVar !== false){
// do whatever...
}
If you can't user "false" you can just empty string '' or any other value that will not appear there.
I need to check if an event has an offer and i have made this function
public function hasAcceptedOffer()
{
foreach ($this->offers as $offer) {
if( $offer->accepted == 1 ){
return true;
} else {
return false;
}
}
But i think this can be made better, more optimized. Because if there are a lot of offers i don't want to go through all of them. What i want is that if a function finds an offer that is accepted it should stop further iteration.
I think you did good here.
You can remove the else part by doing this
public function hasAcceptedOffer()
{
foreach ($this->offers as $offer) {
if( $offer->accepted == 1 ){
return true;
}
}
return false;
}
Assuming you only care if any offer was accepted, and you don't need to know which one, I like to do it like this:
public function hasAcceptedOffer()
{
foreach($this->offers as $offer) {
if($offer->accepted !== 1)
continue;
return true;
}
return false;
}
Each iteration of the loop will quickly skip to the next one if it doesn't match your desired criteria, it will return immediately when it finds the first positive result and skip processing the others (since you don't care anyway) and return false if no matches are found.
If you want to collect the offers that were accepted, you can amend it like so:
public function getAcceptedOffers()
{
$results = array();
foreach($this->offers as $offer) {
if($offer->accepted !== 1)
continue;
$results[] = $offer;
}
return $results;
}
I loop through the values of a form, to check that each field has 4 digits. My problem is currently it validates true or false only on the match for the first field $card1...
function cardcheck ($card1,$card2,$card3,$card4)
{
$cards = array($card1,$card2,$card3,$card4);
$regex = "/[0-9]{4}/";
for ($i=0;$i<4;$i++)
if (! preg_match ($regex,$cards[$i]))
{
return false;
}
else
{
return true;
}
}
You're returning (by using return ...) something in the first iteration every time (boolean condition with an else).
You need to put the return true outside the loop statement:
function cardcheck ($card1,$card2,$card3,$card4)
{
$cards = array($card1,$card2,$card3,$card4);
$regex = "/[0-9]{4}/";
for ($i=0;$i<4;$i++) {
if (! preg_match ($regex,$cards[$i])) {
return false;
}
}
return true;
}
function cardcheck ($card1,$card2,$card3,$card4)
{
$cards = array($card1,$card2,$card3,$card4);
$regex = "/[0-9]{4}/";
for ($i=0;$i<4;$i++)
if (! preg_match ($regex,$cards[$i]))
{
return false;
}
return true;
}
Is there a way to stop an array_walk from inside the anonymous function ?
Here is some sample code (that works) to show what I mean, that checks if an array has only numeric values.
$valid = true;
array_walk($parent, function ($value) use (&$valid) {
if (!is_numeric($value)) {
$valid = false;
}
});
return $valid ? 'Valid' : 'Invalid';
If I have a big enough array, and the first entry is invalid, the rest of the (redundant) checks are still done, so I would like to stop the execution.
Using break / continue doesn't work (error: Fatal error: Cannot break/continue 1 level in ...).
Note: I don't want to rewrite the code, I just want to know IF this is possible.
As stated, theoretically it's possible but I'd advise against it. Here's how to use an Exception to break out of the array_walk.
<?php
$isValid = false;
$array = range(1, 5);
try {
array_walk($array, function($value) {
$isAMagicNumber = 3 === $value;
if ($isAMagicNumber) {
throw new Exception;
}
});
}catch(Exception $exception) {
$isValid = true;
}
var_dump($isValid);
/*
bool(true)
*/
You can put a static flag inside the anonymous function:
array_walk($ary, function($item) {
static $done = false;
if($done) {
return;
}
// … your code
if($myBreakCondition) {
$done = true;
return;
}
});
This doesn’t actually stop the iteration, but all further cycles after the flag is set simply do nothing. Not very efficient, but it might work without any greater performance impact if the arrays iterated are not too large.
In your case, the code would be:
$valid = true;
array_walk($parent, function($value) use(&$valid) {
static $done = false;
if($done) {
return;
}
if(!is_numeric($value)) {
$valid = false;
$done = true;
return;
}
});
return $valid ? 'Valid' : 'Invalid';
But actually it won’t be much difference if there was no “break” at all. Only the “false” would be assigned for every invalid value, which does not matter as the result would be still false. Maybe it would be even more efficient that my static variable cheat.
Personally in your case I would use array_filter instead:
$valid = count(array_filter($parent, 'is_numeric')) == count($parent);
or just
$valid = array_filter($parent, 'is_numeric')) == $parent;
If all values in the $parent array are numeric, they would be all present after the filtering. On the other hand, any non-numeric value in the array would affect the contents (decreasing the item count) in the filtered array and the comparison would yield false.