# String range membership

**URL:** <https://www.ruby-forum.com/t/string-range-membership/48675>\
**Category:** Ruby\
**Created:** [November 23, 2005, 7:44am UTC](https://www.ruby-forum.com/t/string-range-membership/48675 "2005-11-23T07:44:06Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![warrenbrown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/f9ae1b/32.png) [@warrenbrown](https://www.ruby-forum.com/u/warrenbrown)\
**Post date:** [November 23, 2005, 7:44am UTC](https://www.ruby-forum.com/t/string-range-membership/48675/1 "2005-11-23T07:44:06Z")

</div>

All,

```
I ran across some code that was trying to validate that an integer

```

was in a given range, however the integer and the range were Strings.  
The problem boils down to this:

> ruby -e “p (‘1’…‘10’).member?(‘2’)”  
> false

```
Given that...

```

> ruby -v -e “(‘1’…‘10’).each {|s| p s}”  
> ruby 1.8.2 (2004-12-25) [i386-mswin32]  
> “1”  
> “2”  
> “3”  
> “4”  
> “5”  
> “6”  
> “7”  
> “8”  
> “9”  
> “10”

```
...it seems like ('1'..'10').member?('2') should return true. The

```

problem lies in range.c, in the range\_each\_func() method. This method  
starts with the first value, then calls succ() to get the next value,  
breaking out of the loop when the value is no longer less than or equal  
to the ending value (or strictly less than the ending value on an  
exclusive range). Unfortunately, for the given string range this  
happens immediately, since ‘2’ \> ‘10’.

```
I suppose that it could be argued that this is not a bug, but that

```

would be a difficult argument to win. Also, I need to make sure that  
this is still a bug in the latest version of Ruby. Unfortunately, I’m  
too sleepy to investigate further or create a patch for this tonight,  
but I’ll try to work on it some more tomorrow night (assuming nobody  
else fixes it first).

```
- Warren B.
```

---

<div class="post-metadata">

**Author:** ![warrenbrown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/f9ae1b/32.png) [@warrenbrown](https://www.ruby-forum.com/u/warrenbrown)\
**Post date:** [November 23, 2005, 8:56am UTC](https://www.ruby-forum.com/t/string-range-membership/48675/2 "2005-11-23T08:56:29Z")

</div>

On 23/11/05, Warren B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> “9”  
> I suppose that it could be argued that this is not a bug, but that  
> would be a difficult argument to win. Also, I need to make sure that  
> this is still a bug in the latest version of Ruby. Unfortunately, I’m  
> too sleepy to investigate further or create a patch for this tonight,  
> but I’ll try to work on it some more tomorrow night (assuming nobody  
> else fixes it first).
> 
> ```
> - Warren B.
> 
> ```

I’d argue that it is not a bug, as there is no unique isomorphie from  
strings to integers. Some well known functions would be hex, octal and  
decimal encoding. I.e. ‘2’ … ‘10’ could be understood as 2 … 8, or  
2 … 16 or 2 … 10 or error … 2 depending on the base.

Only you can now what the string means, so convert it to an integer  
and do the range test on integers.

So I think you should save your time on creating the patch and  
preferably fix the application code.

Brian

–  
[http://ruby.brian-schroeder.de/](http://ruby.brian-schroeder.de/)

Stringed instrument chords: [http://chordlist.brian-schroeder.de/](http://chordlist.brian-schroeder.de/)

---

<div class="post-metadata">

**Author:** ![warrenbrown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/f9ae1b/32.png) [@warrenbrown](https://www.ruby-forum.com/u/warrenbrown)\
**Post date:** [November 23, 2005, 9:20am UTC](https://www.ruby-forum.com/t/string-range-membership/48675/3 "2005-11-23T09:20:37Z")

</div>

Brian Schröder wrote:

> I’d argue that it is not a bug, as there is no unique isomorphie from  
> strings to integers. Some well known functions would be hex, octal and  
> decimal encoding. I.e. ‘2’ … ‘10’ could be understood as 2 … 8, or  
> 2 … 16 or 2 … 10 or error … 2 depending on the base.
> 
> Only you can now what the string means, so convert it to an integer  
> and do the range test on integers.

I was going to make that argument, but I realized that #each (by way of  
#succ) _does_ have some extra knowledge (or assumptions) about strings,  
and it’s pretty smart:

irb(main):003:0\> (‘1.1’…‘10.1’).each {|s| p s}  
“1.1”  
“1.2”  
“1.3”  
“1.4”  
…  
…  
“9.6”  
“9.7”  
“9.8”  
“9.9”  
“10.0”  
“10.1”  
=\> “1.1”…“10.1”  
irb(main):004:0\> (‘1.6.4’…‘1.8.3’).each {|s| p s}  
“1.6.4”  
“1.6.5”  
“1.6.6”  
“1.6.7”  
“1.6.8”  
“1.6.9”  
“1.7.0”  
“1.7.1”  
“1.7.2”  
“1.7.3”  
“1.7.4”  
“1.7.5”  
“1.7.6”  
“1.7.7”  
“1.7.8”  
“1.7.9”  
“1.8.0”  
“1.8.1”  
“1.8.2”  
“1.8.3”  
=\> “1.6.4”…“1.8.3”

I guess it is just impractical for Range#member? to test using #succ.

---

<div class="post-metadata">

**Author:** ![warrenbrown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/f9ae1b/32.png) [@warrenbrown](https://www.ruby-forum.com/u/warrenbrown)\
**Post date:** [November 23, 2005, 9:28am UTC](https://www.ruby-forum.com/t/string-range-membership/48675/4 "2005-11-23T09:28:39Z")

</div>

Just playing with it around but…

irb(main):057:0\> (‘1’…‘10’).each { |i| puts i }  
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
=\> “1”…“10”  
irb(main):058:0\> (‘1’…‘10’).each { |i| case when i == ‘2’ ; puts “two”  
else puts i end}  
1  
two  
3  
4  
5  
6  
7  
8  
9  
10  
=\> “1”…“10”  
irb(main):059:0\>

---

<div class="post-metadata">

**Author:** ![warrenbrown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/f9ae1b/32.png) [@warrenbrown](https://www.ruby-forum.com/u/warrenbrown)\
**Post date:** [November 23, 2005, 9:20am UTC](https://www.ruby-forum.com/t/string-range-membership/48675/5 "2005-11-23T09:20:37Z")

</div>

Hi,

In message “Re: [BUG] string range membership”  
on Wed, 23 Nov 2005 15:41:32 +0900, “Warren B.”  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) writes:  
| I ran across some code that was trying to validate that an integer  
|was in a given range, however the integer and the range were Strings.

include? and member? compares with beg \<= val \<= end, which is  
dictionary order for strings. Unfortunately strings generated from  
using succ is not in dictionary order. I’m not sure how to solve  
this.

```
						matz.

```

---

<div class="post-metadata">

**Author:** ![warrenbrown](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/f9ae1b/32.png) [@warrenbrown](https://www.ruby-forum.com/u/warrenbrown)\
**Post date:** [November 23, 2005, 2:04pm UTC](https://www.ruby-forum.com/t/string-range-membership/48675/6 "2005-11-23T14:04:41Z")

</div>

> I’m not sure how to solve this.

This was discussed sometime ago. The solution (mostly arrived at by  
Peter V.) is to use a different comparision method. In  
Facets you’ll find the #cmp method, which is part of the base methods,  
and which is used by the Interval class --a true Interval as opposed to  
what Range is.

def cmp(other)  
return -1 if length \< other.length  
return 1 if length \> other.length  
self \<=\> other  
end

Of course this won’t be of use to tuple forms like “1.18.12”, but in  
such cases a Tuple object is in order anyway.

T.
