I am looking to develop a search function that allows users to just search for the item, or modify their search with a price range in brackets. So that is to say if they are looking for a car, then they can enter either car and receive all cars in the database or they can enter car (100, 299) or car(100, 299) and receive only cars in the database with the price range of 100 to 299.
Before what I did was three different explode function calls, but that was cumbersome and looked ridiculously ugly. I also tried to put the the brackets in an array and then compare that against the word searched (a word is basically an array of characters) but that didn't work. Finally I have been reading up on strpos and substr but they don't seem to fit the requirements as strpos returns the first occurrence of the the character and substr returns the characters within a specified length after a specific occurrence.
So for example the problem with strpos is the user can just enter ( and no ) bracket and I'll make a call to my search function with who knows what. And for example the problem with substr is that the price range can vary wildly.
You can use preg_match to parse the search string - I'm assuming that's the part you're having issues with.
if (preg_match('/car ?\(([^,]+), ?([^\)]+)\)/', $search_text, $matches)) {
$low_price = $matches[1];
$high_price = $matches[2];
//do your price filtering here
}
The regular expression may need a little tweaking, I don't remember offhand if parentheses need to be escaped in character classes.
Yes, Sam is right. You should do this with regular expressions.
Look for preg_match() on the documentation
To complete his answer, the regular expression for your case is:
$regex = "^([a-zA-Z]+)\s\(([0-9]+),([0-9]+)\)$"
if (preg_match($regex, $search_text, $matches)) {
$type = $matches[0];
$low_price = $matches[1];
$high_price = $matches[2];
//do your price filtering here
}
Be careful, as the array containing matches starts at index 0, not one.
Related
I Made a PIN authentication on my website, and I don't want my user using common PINs like 12345, 11111, 121212, etc.
I tried this
if($PIN=="111111" || $PIN="222222"){
echo "This PIN is common";
}
But I think that Will be too long for a simple function?
How to simplify it?
Your problem is actually quite simple, you want, for example, to avoid pins that have multiples iterations of a same character in a row OR/AND avoid pins that have a same character repeated more than X times in a string.
Using Regex we can easily achieve something like this: For example, the following will return 1 if 3 characters or more are in a row.
<?php
$pin = '111025';
if ( preg_match( '/(.)\1{2}/', $pin ) ) {
return true;
} else {
return false;
}; ?>
Learn more
RegEx.
A regular expression is a sequence of characters that forms a search
pattern. When you search for data in a text, you can use this search
pattern to describe what you are searching for.
Function
Description
preg_match()
Returns 1 if the pattern was found in the string and 0 if not
( )
You can use parentheses ( ) to apply quantifiers to entire patterns. They also can be used to select parts of the pattern to be used as a match
.
Find just one instance of any character
n{x}
Matches any string that contains a sequence of X n's
PHP RegEx # https://www.w3schools.com/php/php_regex.asp
I need to match longest word of given string using regex:
for example given string
S = "hello night axe axbxbxx prom etc..."
character set 1 = [abcdexy]
character set 2 = [mnrpo]
I need to get only one word that match 2 constriants, all the word should contain characters from one set only and the chosen word should be the longest, I tried to solve this using php regex such as:
preg_match("/\b[abcdexy]+/",$s, $match1);
preg_match("/\b[mnrpo]+/",$s, $match2);
if(strlen($match1[0]) > strlen($match2[0]))
{
//output match1[0];
}
else
{
//output match2[0]
}
The expected output should be axbxbxx since it contain only characters from set 1 and it is the longest between words that belong to one of the two sets.
My question is, can I make this work using only regex without need for strlen() testing?
You can write a single regex expression that uses a pipe to match both character ranges, then sort the matched values by descending length and access the first element's value.
Code: (Demo)
$string='hello proxy night pom-pom-mop axe prom etc decayed';
if (preg_match_all('~\b(?:[a-exy]+|[m-pr]+)\b~', $string, $out)) {
usort($out[0], function($a, $b) {return strlen($b) - strlen($a);}); // or spaceship operator if you like
echo $out[0][0];
} else {
echo "no matches";
}
Output:
decayed
The above method is not "tie-aware" so if you have two values or more values that share the highest length, you will only get one value in the output. I think you need to build in some additional logic to handle these fringe cases like:
Output all highest length values or
Set a secondary criteria to break ties on length
I'll not bother coding up these solution extensions since I prefer not to go down rabbit holes.
I've a part of an xml that i'm importing that is not in a regular order. It could be for example:
87||1|#88||2|#89||2|50198#41||1|#3||1|117#20|||#6|20|1|#24|||78#145|5||#36|||90#37|||96#29|||67#26|||#27|||#25|||
I create a function like this:
function caratteristiche1($title) {
$title=substr($title,11,1);
return $title;
}
to receive the value of #88 but sometimes #88 is not in that position, and other times #88 is not present.
I would like to use a function that will search for #88 and give as result the value present after the 2 subseguent pipes.
What can i do?
Thank you so much!
If the distance between the #88 and the two pipes is identical in all cases, you can use a Regular Expression with a "positive lookbehind assertion", see http://php.net/manual/en/regexp.reference.assertions.php
If not, you probably need to use plain PHP to locate the #88, then take the remaining substring from there on and search for the two pipes.
EDIT after your answer of "NO":
In this case, I wouldn't do it with RegEx.
Try something like that (might not be 100% accurate syntax):
$pos88 = strpos('#88', $string);
newStr = substr($string, $pos88);
$posPipes = strpos('||', $newStr);
// ... and so forth ...
I want to be able to effectively match a string with a number of regular expressions to determine what this string represents.
^[0-9]{1}$ if string matches it is of type 1
^[a-x]{300}$ if string matches it is of type 2
... ...
Iterating over a collection containing all of the regular expressions every time I want to match a string is way too heavy for me.
Is there any more effective way? Maybe I can compile these regexps into one big one? Maybe something that works like Google Suggestions, analysing letter after letter?
In my project, I am using PHP/MySQL, however I will be thankful for a clue in any language.
Edit:
Operation of matching a string will be very frequent and string values will vary.
What you could do, if possible, is grouping your regexes together and determine in which group a string belongs.
For instance, if a string doesn't match \d, you know there is no digit in it and you can skip all regexes that require one. So (for instance) instead of matching against +300 regexes, you can narrow that down to just 25.
You can sum up your regexes like this:
^([0-9])|([a-x]{300})$
Later, if you get more regex, you can do this:
^([0-9])|([a-x]{300})|([x-z]{1,5})|([ab]{2,})$...
Then use this code:
$input=...
preg_match_all('#^([0-9])|([a-x]{300})$#', $input, $matches);
foreach ($matches as $val) {
if (isset($val[1])) {
// type 1
} else if (isset($val[2])) {
// type 2
}
// and so on...
}
Since the regexes are going to be changing, I don't think you can get a generic answer - both your regex(es), and the way you handle them will need to evolve. For now, if you're looking to optimize the processing of your script, test for known strings before evaluating using something like indedOf to lighten the regex load.
For instance, if you have 4 strings:
asdfsdfkjslkdujflkj2lkjsdlkf2lkja
100010010100111010100101001001011
101032021309420940389579873987113
asdfkajhslkdjhflkjshdlfkjhalksjdf
Each belongs to a different "type" as you've described it, so you could do:
//type 1 only contains 0 or 1
//type 2 must have a "2"
//type 3 contains only letters
var arr = [
"asdfsdfkjslkdujflkj2lkjsdlkf2lkja",
"100010010100111010100101001001011",
"101032021309420940389579873987113",
"asdfkajhslkdjhflkjshdlfkjhalksjdf"
];
for (s in arr)
{
if (arr[s].indexOf('2') > 0)
{
//type 2
}
else if (arr[s].indexOf('0') > 0)
{
if ((/^[01]+$/g).test(arr[s]))
//type 1
else
//ignore
}
else if ((/^[a-z]+$/gi).test(arr[s]))
//type 3
}
See it in action here: http://jsfiddle.net/remus/44MdX/
I'm trying to stop users searching with terms that give far too many results.
For example, I'd like users to be able to search for "Big Island" but not search for "Island".
I tried this:
$array = array("island", "islands", "island's", "islet", "ilsets", "reef", "reefs", "shoal", "shoals");
if (0 < count(array_intersect(array_map('strtolower', explode(' ', $searchTerm)), $array)))
{
echo "No results. The search term used was too general.";
exit();
}
But that stops the search for any phrase with the stop words in it.
I guess I'm looking for something that goes like:
if the string contains this word or that word (and only one of those words!) stop what you're doing, else carry on...
look at the strstr function it may help you http://php.net/manual/en/function.strstr.php
Maybe look at searching after removing "stop words" which are words like "the" "and" etc. So remove the "stop words", then check if the search string is empty. Also make sure to add your other words to the stop words list.
Try looking at in_array()
That way you can just say
if (in_array($searchterm,$array))
{
// stop searching
}
Maybe let the user search and then present an "Related searches" à la Google...
Why don't you try with regular expressions - here is a simple demo. You can of course generate the character groups (big|small) etc. from predefined arrays
$regex = '/^(big|small)\s+(Island|islet|reef)$/';
if ( 1 === preg_match($regex, 'big reef ') {...}