flounder Posted February 21, 2011 Share Posted February 21, 2011 Hello all, I have this function: strncasecmp($find, $search, strlen($find)) == 0 It returns records from a csv array, $search $find contains the first letter of the last name field, A, B etc. What I would like to do is narrow down the number of records returned to a limited range af letters for example Aa to Ak, Al to Ar etc How would I go about doing this? Thanks in advance. Quote Link to comment Share on other sites More sharing options...
.josh Posted February 21, 2011 Share Posted February 21, 2011 /** * @param string $base The base string to check for at the beginning of $search * @param string $range The range of letters to look for after $base. Should be "a-r","b-x" etc... * @param string $search The string to be checked */ function isMatch($base,$range,$search) { $base = preg_quote($base); if (!preg_match('~^[a-z]-[a-z]$~i',$range)) $range = 'a-z'; return preg_match('~^'.$base.'['.$range.']~i',$search); } example: $list = array('apple','orange','aardvark','aluminum','area','addict','banana','yellow','zoo','oral','oracle'); $find = "A"; $range = "a-k"; foreach($list as $search) { echo $search . " : "; if (isMatch($find,$range,$search)) { echo "matched"; } else { echo "not matched"; } echo "<br/>"; } output: apple : not matched orange : not matched aardvark : matched aluminum : not matched area : not matched addict : matched banana : not matched yellow : not matched zoo : not matched oral : not matched oracle : not matched Quote Link to comment Share on other sites More sharing options...
flounder Posted February 21, 2011 Author Share Posted February 21, 2011 Hi Crayon Violent, that's just what I was looking for. Thanks very much! Quote Link to comment Share on other sites More sharing options...
flounder Posted February 22, 2011 Author Share Posted February 22, 2011 Hello again, I'm totally new to regular expressions and pattern matching and they are daunting to say the least. The isMatch($base,$range,$search) function provided by Crayon Violet works like a charm for the first two letters. It now appears I need to filter on the first three letters. As far as I can tell, that may be accomplished by inserting {3} somewhere. Is that correct and where do I insert the {3}? !preg_match('~^[a-z]-[a-z]{3}$~i',$range) doesn't work. Thanks again. Quote Link to comment Share on other sites More sharing options...
.josh Posted February 22, 2011 Share Posted February 22, 2011 edit: reposting soon Quote Link to comment Share on other sites More sharing options...
.josh Posted February 22, 2011 Share Posted February 22, 2011 Okay modified function: /** * @param string $subRanges Array of range of letters to look for after $base. Should be "a-r","b-x" etc... * @param string $search The string to be checked */ function isMatch($subRanges,$search) { if (!is_array($subRanges)) $subRanges = array($subRanges); foreach ($subRanges as $k => $v) $subRanges[$k] = (preg_match('~^[a-z]-[a-z]$~i',$v)) ? '['.$v.']' : preg_quote($v); $subRanges = implode('',$subRanges); return preg_match('~^'.$subRanges.'~i',$search); } // end isMatch Okay basically I combined $base and $range into a single argument $subRanges, and you can pass a single string or an array of strings as the first argument. Passing a single string like 'a' or 'abc' will make it look for that exact string. Passing a hyphenated string like 'a-z' will make it look for a range. You can mix and match passing a range or literal string for each element in $subRanges. Examples: Match if $search starts with 'a' $range = 'a'; $search = 'apple'; echo isMatch($range,$search); // 1 (true) Match if $search starts with 'aa' $range = 'aa'; $search = 'aardvark'; echo isMatch($range,$search); // 1 (true) Match if $search starts with 'a', followed by 'a' (effectively same thing as previous example) $range = array('a','a'); $search = 'aardvark'; echo isMatch($range,$search); // 1 (true) Match if $search starts with 'a', followed by 'b' $range = array('a','b'); $search = 'about'; echo isMatch($range,$search); // 1 (true) Match if $search starts with 'a', followed by 'a' or 'b' $range = array('a','a-b'); $search = 'about'; echo isMatch($range,$search); // 1 (true) Match if $search starts with any letter, followed by 'a' or 'b', followed by any letter between 'a' and 'o' (inclusive) $range = array('a-z','a-b','a-o'); $search = 'about'; echo isMatch($range,$search); // 1 (true) Match if $search starts with any letter, followed by 'abc', followed by 'z' $range = array('a-z','abc','z'); $search = 'aabcd'; echo isMatch($range,$search); // 0 (false) Match if $search starts with any letter, followed by 'abc', followed by any letter $range = array('a-z','abc','a-z'); $search = 'aabc'; echo isMatch($range,$search); // 0 (false) Quote Link to comment Share on other sites More sharing options...
flounder Posted February 22, 2011 Author Share Posted February 22, 2011 Hi Crayon Violet, I'll try that in a minute, but just looking at the function shouldn't the $subRanges[$k] = (preg_match('~^[a-z]-[a-z]$~i',$v)) ? '['.$v.']' : preg_quote($v); $subRanges = implode('',$subRanges); return preg_match('~^'.$subRanges.'~i',$search); be enclosed in curly brackets? Quote Link to comment Share on other sites More sharing options...
.josh Posted February 22, 2011 Share Posted February 22, 2011 The only thing that is supposed to be in the foreach loop is that first line with the ternary operation. Since you don't need {..} wrapped around just one line of code in a loop (or condition), I left it out. With {...} it would look like this: function isMatch($subRanges,$search) { if (!is_array($subRanges)) $subRanges = array($subRanges); foreach ($subRanges as $k => $v) { $subRanges[$k] = (preg_match('~^[a-z]-[a-z]$~i',$v)) ? '['.$v.']' : preg_quote($v); } $subRanges = implode('',$subRanges); return preg_match('~^'.$subRanges.'~i',$search); } // end isMatch Quote Link to comment Share on other sites More sharing options...
flounder Posted February 22, 2011 Author Share Posted February 22, 2011 Thanks again, Crayon Violet! Since you don't need {..} wrapped around just one line of code in a loop (or condition) I didn't know that, thank you. I tried it without {}, the way you suggested in your last post as well as the way I questioned it, all 3 ways work. This is awesome, I can't thank you enough, I'll mark this solved. PS. for anybody following this thread, in the modified function examples $range should read $subRanges Quote Link to comment Share on other sites More sharing options...
.josh Posted February 22, 2011 Share Posted February 22, 2011 PS. for anybody following this thread, in the modified function examples $range should read $subRanges er...? are you referring to doing : $subRanges = array('a-z','abc','z'); $search = 'aabcd'; echo isMatch($subRanges,$search); // 0 (false) Is that what you are referring to? If so, then it doesn't matter what variable you pass to isMatched(). You can do it as that or $range = array('a-z','abc','z'); $search = 'aabcd'; echo isMatch($range,$search); // 0 (false) or echo isMatch('a','abc'); // 0 (false) or echo isMatch($someOtherVar,$randomVariable); // 0 (false) the function itself internally matches 1st argument with $subRanges, 2nd argument with $search Quote Link to comment Share on other sites More sharing options...
flounder Posted February 22, 2011 Author Share Posted February 22, 2011 Of course you're absolutely right, my mistake! Quote Link to comment Share on other sites More sharing options...
flounder Posted February 22, 2011 Author Share Posted February 22, 2011 Hi Crayon Violent, sorry to bother you. I'm trying to return all records in this range: Can**** to Ciz**** This doesn't work $subRanges = "can-ciz"; and neither does this $subRanges = array('c','an-iz'); What's wrong with my logic? Quote Link to comment Share on other sites More sharing options...
.josh Posted February 22, 2011 Share Posted February 22, 2011 For ranges, the function will only work for single character ranges. If you try to pass "can-ciz" it will just look for that literal string. So from attempts: $subRanges = "can-ciz"; This will look to see if the $search string starts with the literal string 'can-ciz' so for instance $search = "can-cizblahblah" would return true $subRanges = array('c','an-iz'); This will look to see that $search starts with a "c" followed by literal "an-iz" so if $search = "can-izblahblah" it would return true. In order to look for everything that alphabetically falls between Can* to Ciz* you have to pass it like this: $subRanges = array("c","a-i","n-z"); Quote Link to comment Share on other sites More sharing options...
flounder Posted February 22, 2011 Author Share Posted February 22, 2011 got it! Again, thanks for all your help. Quote Link to comment Share on other sites More sharing options...
.josh Posted February 22, 2011 Share Posted February 22, 2011 hmm I have thought of a potential flaw with the function, depending on what your actual need for this function is... In order to look for everything that alphabetically falls between Can* to Ciz* you have to pass it like this: $subRanges = array("c","a-i","n-z"); Okay as mentioned, the way the function works is that it looks at the $search phrase you give it and compares it to the string/array you pass it, one array element per character if a range is given or block of characters if a literal string is given. So the question is, do you want to return true or false based on what would show up in like a dictionary listing, or do you want it to search for words based off matching ranges of each letter position specified? So In other words: Scenario 1: "In a dictionary, return for me all words that fall between "can*" and "ciz*". example:"cell" should fall between "can" and "ciz" alphabetically, but as-is, the function will return false, because that's not what the function is doing. Scenario 2: "return all words that start with 'c', followed by any one of these letters: 'a,b,c,d,e,f,g,h,i', followed by any one of these letters: 'n,o,p,q,r,s,t,u,v,w,x,y,z' ". This is what the function is currently doing. With "cell", the "c" is matched, then the "e" is matched from "a-i" but then "l" is not in the "n-z" range, so it returns false. So..do you see the difference? Which way were you wanting to do it? Quote Link to comment Share on other sites More sharing options...
flounder Posted February 22, 2011 Author Share Posted February 22, 2011 Hi Crayon Violet, thanks for the follow up. I already ran into that problem. For example, I tried to retrieve all records matching M*** to Mib*** using array("m","a-i","a-b"); It returned only one record although there were 58 records that should have matched. Scenario 1 is what I'd like it to do.... Quote Link to comment Share on other sites More sharing options...
.josh Posted February 23, 2011 Share Posted February 23, 2011 Okay sorry, I guess I misunderstood your needs. Updated function, much simpler: /** * Function to find out whether or not a string falls within an alphabetical range * @param string $subject The string you want to test * @param string $min The start range to match against * @param string $max The end range to match against * @return boolean */ function isMatch($subject, $min, $max) { return ( (substr($subject,0,strlen($min)) >= $min) && (substr($subject,0,strlen($max)) <= $max) ); } // end isMatch 3 arguments: first one is the string you want to test, 2nd argument is the starting range, 3rd argument is the ending range. No passing arrays or hyphenated ranges or nothin'. Example 1: Check if 'something' falls between 'a' and 'z' echo isMatch('something','a','z'); // 1 (true) Example 2: Check if 'something' falls between 'a' and 'c' echo isMatch('something','a','c'); // 0 (false) Example 3: Check if 'something' falls between 'sa' and 'se' echo isMatch('something','sa','se'); // 0 (false) Example 4: Check if 'something' falls between 'sa' and 'sz' echo isMatch('something','sa','sz'); // 1 (true) Example 5: Check if 'cabinet' falls between 'can' and 'ciz' echo isMatch('cabinet','can','ciz'); // 0 (false) Example 6: Check if 'cell' falls between 'can' and 'ciz' echo isMatch('cell','can','ciz'); // 1 (true) Quote Link to comment Share on other sites More sharing options...
flounder Posted February 24, 2011 Author Share Posted February 24, 2011 Hi Crayon Violet, that's awesome, thank you, thank you, thank you! Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.