Jump to content

strncasecmp question


flounder

Recommended Posts

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.

 

 

Link to comment
https://forums.phpfreaks.com/topic/228402-strncasecmp-question/
Share on other sites

/**
* @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

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.

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)

 

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?

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

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

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

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?

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");

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?

 

 

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....

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)

 

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.