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

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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)

 

Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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?

 

 

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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)

 

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

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