If between two values that are strings

Hi guys.

If I needed to check whether a given value was between two predetermined values, I would usually do something like:

if($x >= 100 && $x <= 1000){...}

What I need to do is to do a similar thing with an alphanumeric string. What is the best method for doing it? Does PHP properly support this?

Cheers

Depends on your algorithm.
Just as a quickie wrote up this…could be better I’m sure.


function isBetween ( $str, $min = 'a', $max = 'z' )
{
    $index = array_flip( range( 'a', 'z' ) );

    $min = $index[ $min ]; $max = $index[ $max ];
    $str = $index[ $str[0] ];

    return ( ( $str > $min ) && ( $str < $max ) );
}

var_dump( isBetween( 'monkey', 'b', 's' ) );

First you have to define alphanumeric string comparison rules. Because no one knows what you want to compare and why.
PHP compares strings alphabetically

If I say ‘between “brown” and “smith”’, will it recognice “fitzpatrick” for example

most likely.
but why don’t you try it out?

I can test a couple of examples, yes, but I was hoping that someone would have experience and be able to tell me whether there are likely to be spurious results that I can’t predict

There are no strict rules for string comparison.
So, no answer for your particular case unless you define complete set of rules.
It is you, who have to answer, what string is less - “99” or “1000” and vice versa.

alphanumeric…

Be careful here. If both strings are integer like, php will compare them as numbers, not strings. strcmp() won’t do this.


var_dump('2' > '10');//f
var_dump(strcmp('2', '10') > 0);//t

strcmp() compares byte by byte until it finds a non matching byte. At that point, the non matching byte is compared to see which is greater. Thats why it gave the above result, because the first byte didn’t match, and 2(ascii code 50) is greater than 1(ascii code 49).

Thanks guys, for the constructive pointers. The problem I face is that the values that are passed to it could be numerical, they could be strings, but in all cases they should be of the same type at any given time, so for example:

is 4 between 1 and 5?
is James between Brown and Smith
is NG16 2NB between NG1 1AA and NG99 9ZZ
is B85 between B74 and B89

If you see what I mean? I just need a common function that I can pass any of these to. If I need to do something like is_numeric(), is_string() etc and do a slightly different calculation for each then that’s fine, I just want to ensure that I am handling strings the same way that I handle numbers, ie I that the code identifies which I need to use and just does it, rather than needing a human to set it up

If you always pass matching types, then that will eliminate a lot of php’s comparison magic. But, you need to decide whether or not you want php to compare numeric strings numerically, or stay loyal to their string types and be compared as strings.

Another consideration for string comparison, is the difference between normal string comparison, and a natural(human like) string comparison. See the behavior of strnatcmp()

Well basically, what’s going to happen, is that the system will receive data from some aged flat-file system (not even a database) that will include various codes. We can change them within the PHP but they’re drop-down select boxes, so the values are validated and limited. When the form is submitted then rules that I’ve been working on elsewhere on here will check whether something is equal to, not equal to, or between (as examples) and then progress the job in a particular direction or drop it altogether. So, if the value is purely numeric (ie service arrangement 12) and we want to say that everything between 5 and 15 should be handled as X, then we’ll need that to be numeric. Everything that is compared will be numeric in this example, so I just need to know if the submitted value is within range. Likewise if we say that all manufacturers between Medion and Sony are handled by one team, then we need the rules to say Lenovo (for example) is NOT within this range and will go to the rest of the teams. Just examples, but hopefully you see what I mean. I will never need to see whether “Sony” is between “5” and “NG99 9ZZ” for example.

So, if I’m ensuring that the variable types are correct, ie numeric, string etc, then the code I posted originally will work, right?

You still haven’t clarified your definition of “work correctly” because you haven’t addressed the desired types of comparison for the different types of input. I’ve brought up the major issues you need to think about.

But it sounds like you want the behavior of the code in your first post, at least for most stuff.

It looks as if nobody can help you with this till you can fully define some use cases, and its accompanying edge cases, in order before a candidate algorithm be tested.

I’m sorry guys, I thought I’d defined it already. Beyond my previous examples I’m not sure what else I can define? Can someone give me an example of what kind of information I should be providing, short of the aforementioned examples and explanations?

Thanks

is NG16 2NB between NG1 1AA and NG99 9ZZ

Here for example, you seem to suggest that the algo should be working its way automagically character by character, comparing string to string, then integer to integer?

Should it go something like :

First characters are the same (N), so move to next character (G), they are the same so go to the next character, thats a number, and its between the bounds, (1 and 9) but go to the next character and thats a bounds check between <nothing or null or space> and 9.

It might be best to try and successfully identify that you are dealing with what looks like a UK postcode, and pass the value to a special postcode checking function.

Whether you do that or not might well depend on how many UK postcodes you are expecting to come across.

In this case some tests might be:

NG16 2NB

vs

NG1 1AA | NG99 9ZZ
NG100 1AA | NG99 9ZZ
N100 1AA | NG99 9ZZ
NG1 1AA | NG99 9ZZ
NG99 9ZZ | NG1 1AA
NG1 | NG1 1AA

and so on… but presented in a way that others can emulate the tests, such as in an array format:


$test = array( 
  array( 'NG1 1AA' , 'NG99 9ZZ', true)
, array( 'NG100 1AA' , 'NG99 9ZZ' , false )
);

Then we can loop through the array testing NG16 2NB trying to match the 3rd array value.

Thats how I’d define the tests, especially if I wanted others to pitch in and help me.

OK, cheers, I appreciate that. To be honest, this is the kind of answer I was looking for. My original question was just whether that simple code would work or whether there would be some weird side effects depending on some of the examples that we may give it. That tells me that there may well be and I’ll need to consider something different, with pointers. That’s constructive and that helps me.

I won’t be able to do much more today because I’m busy with other things (interviews, yay) but I’ll definitely take that on board and see what I can come up with. Cheers

What started off as a simple question has grown into something far more complex.

As you previously said, if a value is numeric, then go into numeric bounds checking mode, if it is a string go into alphabetical mode etc.

But when you chuck in a postcode the complexity of your fairly simple algorithm grows enormously - unless, you can either tell your application it has a postcode or you detect (using pattern matching) you are dealing with a postcode - and then hive that off as a “special case” and deal with it separately.

The solution you choose may depend on how many of these “special cases” you dig up, but the numeric and alphabetical bounds checking sounds easy enough to pull off, if that would satisfy some 80:20 rule then you could get that working quickly.

Even then though, you’d need to create some test cases, especially if you have any strings starting with zero which may be understood by PHP to be numeric values.

Yep, thanks for that. You’re right, it did start off as a simple question. What I was originally looking for was “generically, will this work, or does someone with experience of this kind of comparison have any pointers on what to look out for”. Theoretically almost any type of data could be passed through, and for now (because we’re in a rush) we’ll have to provide something a bit more straight forward and educate the people who are programming the parameters in for comparison. I’m not too fussed on the postcode comparison because the system doesn’t need to store it, but I figured it was a good example of how we might break the earlier successful example.

So, thanks to everyone who gave constructive feedback. I have enough to go and try new things. I will try sending some odd values through it and see how it reacts and see what I can do to fix anything odd.

Thanks again

When #walkingthedogs I had a thought which might be useful.

The talk of arrays kicked my thinking off, because PHP contains so many sorting functions.

Take a really simple example:


$start = 9 ;
$end = 6 ;
$item = 2 ;

$arr = array(
$start 
, $item
, $end
) ;

sort( $arr ) ;

if( $arr[1] != $item )
  echo 'Sorry, ' . $item . 'out of range';

That way you’d have a common method of running the test, and for strings you’d have access to all those sorting functions.

Actually, this just works with plain sort() too;


$start = "Bob" ;
$end = "Bone-head" ;
$item = "Boris";

Sort is handy because it works its way through all the letters one at a time.

You’d probably need to bone up on all the sort options for those edge cases.

Cheers, another idea to try, thanks a lot