# False positives in editing data

**URL:** <https://rubytalk.org/t/false-positives-in-editing-data/42312>\
**Category:** ruby-talk\
**Created:** [19 November 2007 05:39 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312 "2007-11-19T05:39:59Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Richard3](https://avatars.discourse-cdn.com/v4/letter/r/b5a626/32.png) [@Richard3](https://rubytalk.org/u/Richard3)\
**Post date:** [19 November 2007 05:39 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312/1 "2007-11-19T05:39:59Z")

</div>

Hi All,

Below is a 33-line program that analyzes a set of names.  
The names proper are prefixed with an optional set of period-separated  
numbers.  
The analysis checks for the following, and flags violations:  
&nbsp;&nbsp;1. A number may not start with zeros.  
&nbsp;&nbsp;2. No more that two numbers may be prefixed  
&nbsp;&nbsp;3. Names proper must begin with a non-digit

The program works pretty well, except it produces "false negatives,"  
which I flag on the output displayed following the program. The  
problem is around line 29 when I try to determine if a leading number  
has any initial zero by using an RE and testing for Nil.

I'd welcome any ideas on how to correct my mistake(s), especially with  
suggestion for improved style.

Thanks in advance,  
Richard

Program

> **···**
>
> -------------------------------------------------------------------------------  
> MLN = 2 # MaxLeadingNumbers  
> input = \<\<DATA  
> 05Topic 5  
> 1Topic 1  
> 2.002.1Topic 2.2.1  
> 2.1Topic 2.1  
> 2.2.02Topic 2.2.2  
> DATA  
> input.each { |sName|  
> &nbsp;&nbsp;# Debug  
> &nbsp;&nbsp;puts "\n" + "="\*10 + "DBG", sName, "="\*10+ "DBG"
> 
> &nbsp;&nbsp;#Get leading numbers separated by periods into $1, $2, $13  
> &nbsp;&nbsp;sName =~ /^([\d]+)?\.?([\d]+)?\.?([\d]+)?\.?/
> 
> &nbsp;&nbsp;# Save match variables in n[1] ... n[MLN+1]  
> &nbsp;&nbsp;n = Array.new  
> &nbsp;&nbsp;(1..MLN+1).each { |i| eval %{n[i] = $#{i}} }
> 
> &nbsp;&nbsp;# Debug  
> &nbsp;&nbsp;print "DBG0\>\> "; (1..MLN+1).each { |i| printf("\t#{n[i]}") }; puts  
> &nbsp;&nbsp;# puts "n1=#{n[1]}, n2=#{n[2]}, n3=#{n[3]}"
> 
> &nbsp;&nbsp;# Get and check leading, period-separated numbers in dir. names  
> &nbsp;&nbsp;(1..MLN+1).each { |i|  
> &nbsp;&nbsp;&nbsp;&nbsp;n[i] =~ /^0+/  
> &nbsp;&nbsp;&nbsp;&nbsp;i\_thNumberExists = n[i] ? true : false  
> &nbsp;&nbsp;&nbsp;&nbsp;iThNumbrerHasLeadingZero = i\_thNumberExists && (eval("$#{i}.class ==  
> NilClass") ?  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;true : false)  
> &nbsp;&nbsp;&nbsp;&nbsp;puts "ERROR: Leading zeros in #{n[i]}" if iThNumbrerHasLeadingZero  
> && (i \<= MLN)  
> &nbsp;&nbsp;&nbsp;&nbsp;puts "ERROR: Depth of hierarchy exceeds #{MLN}" if i\_thNumberExists  
> && i \> MLN  
> &nbsp;&nbsp;}  
> }
> 
> Output  
> ---------------------------------------------
> 
> ==========DBG  
> 05Topic 5  
> ==========DBG  
> DBG0\>\> 05  
> ERROR: Leading zeros in 05
> 
> ==========DBG  
> 1Topic 1  
> ==========DBG  
> DBG0\>\> 1  
> ERROR: Leading zeros in 1 [False positive]
> 
> ==========DBG  
> 2.002.1Topic 2.2.1  
> ==========DBG  
> DBG0\>\> 2 002 1  
> ERROR: Leading zeros in 2 [False positive]  
> ERROR: Leading zeros in 002  
> ERROR: Depth of hierarchy exceeds 2
> 
> ==========DBG  
> 2.1Topic 2.1  
> ==========DBG  
> DBG0\>\> 2 1  
> ERROR: Leading zeros in 2 [False positive]  
> ERROR: Leading zeros in 1 [False positive]
> 
> ==========DBG  
> 2.2.02Topic 2.2.2  
> ==========DBG  
> DBG0\>\> 2 2 02  
> ERROR: Leading zeros in 2 [False positive]  
> ERROR: Leading zeros in 2 [False positive]  
> ERROR: Depth of hierarchy exceeds 2
> 
> > Exit code: 0

---

<div class="post-metadata">

**Author:** ![Richard3](https://avatars.discourse-cdn.com/v4/letter/r/b5a626/32.png) [@Richard3](https://rubytalk.org/u/Richard3)\
**Post date:** [19 November 2007 06:40 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312/2 "2007-11-19T06:40:02Z")

</div>

Hi All,

Problem solved!

I went through a convoluted process to determine whether any of the  
initial numbers began with a zero. I simplified it to:

i\_thNumberHasLeadingZero = (n[i] =~ /^0+/) ? true : false

I apologize for raising the question. My excuse is that I was  
flailing about unable to figure out what was wrong. After I posted,  
I took a harder look and realized my big mistake: I needed to use the  
KISS method 🙂

Best wishes,  
Richard

> **···**
>
> On Nov 19, 12:39 am, RichardOnRails \<RichardDummyMailbox58...@uscomputergurus.com\> wrote:
> 
> > Hi All,
> > 
> > Below is a 33-line program that analyzes a set of names.  
> > The names proper are prefixed with an optional set of period-separated  
> > numbers.  
> > The analysis checks for the following, and flags violations:  
> > &nbsp;&nbsp;1. A number may not start with zeros.  
> > &nbsp;&nbsp;2. No more that two numbers may be prefixed  
> > &nbsp;&nbsp;3. Names proper must begin with a non-digit
> > 
> > The program works pretty well, except it produces "false negatives,"  
> > which I flag on the output displayed following the program. The  
> > problem is around line 29 when I try to determine if a leading number  
> > has any initial zero by using an RE and testing for Nil.
> > 
> > I'd welcome any ideas on how to correct my mistake(s), especially with  
> > suggestion for improved style.
> > 
> > Thanks in advance,  
> > Richard
> > 
> > Program  
> > -------------------------------------------------------------------------------  
> > MLN = 2 # MaxLeadingNumbers  
> > input = \<\<DATA  
> > 05Topic 5  
> > 1Topic 1  
> > 2.002.1Topic 2.2.1  
> > 2.1Topic 2.1  
> > 2.2.02Topic 2.2.2  
> > DATA  
> > input.each { |sName|  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Debug  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "\n" + "="\*10 + "DBG", sName, "="\*10+ "DBG"
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#Get leading numbers separated by periods into $1, $2, $13  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sName =~ /^([\d]+)?\.?([\d]+)?\.?([\d]+)?\.?/
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Save match variables in n[1] ... n[MLN+1]  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;n = Array.new  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(1..MLN+1).each { |i| eval %{n[i] = $#{i}} }
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Debug  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "DBG0\>\> "; (1..MLN+1).each { |i| printf("\t#{n[i]}") }; puts  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# puts "n1=#{n[1]}, n2=#{n[2]}, n3=#{n[3]}"
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Get and check leading, period-separated numbers in dir. names  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(1..MLN+1).each { |i|  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;n[i] =~ /^0+/  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i\_thNumberExists = n[i] ? true : false  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iThNumbrerHasLeadingZero = i\_thNumberExists && (eval("$#{i}.class ==  
> > NilClass") ?  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;true : false)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "ERROR: Leading zeros in #{n[i]}" if iThNumbrerHasLeadingZero  
> > && (i \<= MLN)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "ERROR: Depth of hierarchy exceeds #{MLN}" if i\_thNumberExists  
> > && i \> MLN  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
> > 
> > }
> > 
> > Output  
> > ---------------------------------------------
> > 
> > ==========DBG  
> > 05Topic 5  
> > ==========DBG  
> > DBG0\>\> 05  
> > ERROR: Leading zeros in 05
> > 
> > ==========DBG  
> > 1Topic 1  
> > ==========DBG  
> > DBG0\>\> 1  
> > ERROR: Leading zeros in 1 [False positive]
> > 
> > ==========DBG  
> > 2.002.1Topic 2.2.1  
> > ==========DBG  
> > DBG0\>\> 2 002 1  
> > ERROR: Leading zeros in 2 [False positive]  
> > ERROR: Leading zeros in 002  
> > ERROR: Depth of hierarchy exceeds 2
> > 
> > ==========DBG  
> > 2.1Topic 2.1  
> > ==========DBG  
> > DBG0\>\> 2 1  
> > ERROR: Leading zeros in 2 [False positive]  
> > ERROR: Leading zeros in 1 [False positive]
> > 
> > ==========DBG  
> > 2.2.02Topic 2.2.2  
> > ==========DBG  
> > DBG0\>\> 2 2 02  
> > ERROR: Leading zeros in 2 [False positive]  
> > ERROR: Leading zeros in 2 [False positive]  
> > ERROR: Depth of hierarchy exceeds 2
> > 
> > \>Exit code: 0

---

<div class="post-metadata">

**Author:** ![Raul\_Parolari](https://avatars.discourse-cdn.com/v4/letter/r/49beb7/32.png) [@Raul\_Parolari](https://rubytalk.org/u/Raul_Parolari)\
**Post date:** [19 November 2007 10:47 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312/3 "2007-11-19T10:47:45Z")

</div>

RichardOnRails wrote:

> Below is a 33-line program that analyzes a set of names.  
> The names proper are prefixed with an optional set of period-separated  
> numbers.  
> The analysis checks for the following, and flags violations:  
> &nbsp;&nbsp;1. A number may not start with zeros.  
> &nbsp;&nbsp;2. No more that two numbers may be prefixed  
> &nbsp;&nbsp;3. Names proper must begin with a non-digit  
> ..  
> I'd welcome any ideas on how to correct my mistake(s), especially with  
> suggestion for improved style.

Richard,

&nbsp;&nbsp;even after your correction, there are things that we can improve in  
your program; the problems I see are:

1) the array of numbers for the prefix is configured with the maximum  
(MLN) nr of components, rather than with the entries that are present  
within the line. This leads to complicated code (evaluating $n variables  
beyond the valid ones, etc).  
2) the regular expression sName for the numbers would need to be updated  
if MLN changes (in fact, it currently contains more values than needed).  
3) the script does not catch if the prefix contains characters other  
than digits and dots. Try eg, prefix '2.!1' ; the prefix will be  
recognized as 2, and consider the entry valid.

So the problem is that the code is very complex, and fragile; the good  
news is that we can have a simpler and more robust solution; let us  
divide the problem in small steps:

1) we first collect everything until the first letter (not included); we  
will consider this the Prefix.  
2) we verify that the Prefix has the format that we want: numbers  
separated by dots.  
3) we then split the Prefix into an array of Numbers.  
4) we verify that the Array size does not exceed the MLN max size.  
5) we then check if any of the entries begins with 0.  
\*) oh, and we will use the /x modifier to make the regexps legible

Each of the previous steps will be one line of code, so we should have a  
very small script; I will comment the lines with the same number used  
above, so you can map every statement with the 'battle plan' above:

class FormatError \< Exception  
# used right now only for unrecoverable errors  
end

input.each do |line|

&nbsp;&nbsp;# debug info  
&nbsp;&nbsp;puts "\n" + "="\*10 + "DBG", line, "="\*10+ "DBG\n"

&nbsp;&nbsp;# 1) collect everything (not greedy) until first letter  
&nbsp;&nbsp;if line =~ /^ (.\*?) [a-zA-Z] /x

&nbsp;&nbsp;&nbsp;&nbsp;prefix = $1  
&nbsp;&nbsp;&nbsp;&nbsp;puts "prefix= '#{prefix}'"

&nbsp;&nbsp;&nbsp;&nbsp;# 2) validate format: numbers separated by digits  
&nbsp;&nbsp;&nbsp;&nbsp;if prefix =~ /^ (?:\d+ [.]?)+ $ /x

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# 3) collect the numbers in an array  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr = prefix.split('.')

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# 4) verify max array size  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts " (Error: depth of hierarchy \> #{MLN}!)" if  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr.length \> MLN

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# 5) any number begins with 0?  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts " (Error: a nr begins with 0!) " if  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr.any? { |v| v =~ /^0/ }

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print " Numbers: ", arr.join(', '), "\n"

&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;raise FormatError, "Prefix format NOT nr.nr.nr.."  
&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "the line has no prefix (option or error?)"  
&nbsp;&nbsp;end

end # input

This program generated, tested with the same data you used, this output:

==========DBG  
05Topic 5  
==========DBG  
prefix= '05'  
&nbsp;&nbsp;(Error: a nr begins with 0!)  
&nbsp;&nbsp;Numbers: 05

==========DBG  
1Topic 1  
==========DBG  
prefix= '1'  
&nbsp;&nbsp;Numbers: 1

==========DBG  
2.002.1Topic 2.2.1  
==========DBG  
prefix= '2.002.1'  
&nbsp;&nbsp;(Error: depth of hierarchy \> 2!)  
&nbsp;&nbsp;(Error: a nr begins with 0!)  
&nbsp;&nbsp;Numbers: 2, 002, 1

==========DBG  
2.1Topic 2.1  
==========DBG  
prefix= '2.1'  
&nbsp;&nbsp;Numbers: 2, 1

==========DBG  
2.2.02Topic 2.2.2  
==========DBG  
prefix= '2.2.02'  
&nbsp;&nbsp;(Error: depth of hierarchy \> 2!)  
&nbsp;&nbsp;(Error: a nr begins with 0!)  
&nbsp;&nbsp;Numbers: 2, 2, 02

As you can see, it seems to work well (it also catches double errors,  
which is nice). Notice that if the max array size had to be changed, we  
just need to modify the MLN value.

I hope this made sense, and that it helped.  
Good luck!

Raul

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Ryan\_Davis1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/ryan_davis1/32/1848_2.png) [@Ryan\_Davis1](https://rubytalk.org/u/Ryan_Davis1)\
**Post date:** [19 November 2007 07:23 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312/4 "2007-11-19T07:23:30Z")

</div>

I realize you solved your problem, but there is a much more insidious underlying issues here:

> > MLN = 2 # MaxLeadingNumbers

MLN

> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sName =~ /^([\d]+)?\.?([\d]+)?\.?([\d]+)?\.?/

sName

> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;n = Array.new

n

> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "DBG0\>\> "; (1..MLN+1).each { |i| printf("\t#{n[i]}") };

nasty compounded lines and obtuse debugging output

> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i\_thNumberExists = n[i] ? true : false  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iThNumbrerHasLeadingZero = i\_thNumberExists &&

i\_thNumberExists  
iThNumbrerHasLeadingZero

ARGH! My eyes! STOP!!!

Ruby is NOT C.

For the love of all that is ruby, please write readable code!

Use English variable names (or whatever your native language is--just use words). Don't use hungarian notation, it doesn't help--hell, your variable names are so ugly you can't even read the misspellings in them. Don't mix camelcase and underscores. Don't use 'n[i] ? true : false' when 'n[i]' would do. Don't debug with logging. Write tests. /[\d]+/ is the same as /\d+/. Those evals are TERRIFYING. Don't use them.

And, most importantly, 2 spaces per indent.

If you follow these suggestions, your code will be much more understandable and less error prone. Really.

> **···**
>
> On Nov 18, 2007, at 22:40 , RichardOnRails wrote:

---

<div class="post-metadata">

**Author:** ![Harry3](https://avatars.discourse-cdn.com/v4/letter/h/54ee81/32.png) [@Harry3](https://rubytalk.org/u/Harry3)\
**Post date:** [19 November 2007 07:42 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312/5 "2007-11-19T07:42:26Z")

</div>

> Problem solved!
> 
> I went through a convoluted process to determine whether any of the  
> initial numbers began with a zero. I simplified it to:
> 
> i\_thNumberHasLeadingZero = (n[i] =~ /^0+/) ? true : false
> 
> I apologize for raising the question. My excuse is that I was  
> flailing about unable to figure out what was wrong. After I posted,  
> I took a harder look and realized my big mistake: I needed to use the  
> KISS method 🙂
> 
> Best wishes,  
> Richard

If you solved your problem then you won't need this.  
But, just in case you are interested in looking at it from a little  
different view....  
It is not a complete solution, just an idea.

inp = \<\<DATA  
05Topic 5  
1Topic 1  
2.002.1Topic 2.2.1  
2.1Topic 2.1  
2.2.02Topic 2.2.2  
DATA

err1 = inp.select{|a| a =~ /^0|\.0/}  
puts "A number may not start with zero" unless err1.empty?  
print err1  
puts  
err2 = inp.select{|b| b =~ /^\d+\.\d+\.\d/}  
puts "No more that two numbers may be prefixed" unless err2.empty?  
print err2

Harry

> **···**
>
> --  
> A Look into Japanese Ruby List in English
> 
> > **[Kakueki.com is for sale | HugeDomains](https://www.hugedomains.com/domain_profile.cfm?d=kakueki.com)**
> >
> > Start using this domain right away. Straightforward domain shopping experience. Quick access to your domain.

---

<div class="post-metadata">

**Author:** ![Richard3](https://avatars.discourse-cdn.com/v4/letter/r/b5a626/32.png) [@Richard3](https://rubytalk.org/u/Richard3)\
**Post date:** [21 November 2007 02:05 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312/6 "2007-11-21T02:05:02Z")

</div>

> RichardOnRails wrote:  
> \> Below is a 33-line program that analyzes a set of names.  
> \> The names proper are prefixed with an optional set of period-separated  
> \> numbers.  
> \> The analysis checks for the following, and flags violations:  
> \> 1. A number may not start with zeros.  
> \> 2. No more that two numbers may be prefixed  
> \> 3. Names proper must begin with a non-digit  
> \> ..  
> \> I'd welcome any ideas on how to correct my mistake(s), especially with  
> \> suggestion for improved style.
> 
> Richard,
> 
> &nbsp;&nbsp;even after your correction, there are things that we can improve in  
> your program; the problems I see are:
> 
> 1) the array of numbers for the prefix is configured with the maximum  
> (MLN) nr of components, rather than with the entries that are present  
> within the line. This leads to complicated code (evaluating $n variables  
> beyond the valid ones, etc).  
> 2) the regular expression sName for the numbers would need to be updated  
> if MLN changes (in fact, it currently contains more values than needed).  
> 3) the script does not catch if the prefix contains characters other  
> than digits and dots. Try eg, prefix '2.!1' ; the prefix will be  
> recognized as 2, and consider the entry valid.
> 
> So the problem is that the code is very complex, and fragile; the good  
> news is that we can have a simpler and more robust solution; let us  
> divide the problem in small steps:
> 
> 1) we first collect everything until the first letter (not included); we  
> will consider this the Prefix.  
> 2) we verify that the Prefix has the format that we want: numbers  
> separated by dots.  
> 3) we then split the Prefix into an array of Numbers.  
> 4) we verify that the Array size does not exceed the MLN max size.  
> 5) we then check if any of the entries begins with 0.  
> \*) oh, and we will use the /x modifier to make the regexps legible
> 
> Each of the previous steps will be one line of code, so we should have a  
> very small script; I will comment the lines with the same number used  
> above, so you can map every statement with the 'battle plan' above:
> 
> class FormatError \< Exception  
> # used right now only for unrecoverable errors  
> end
> 
> input.each do |line|
> 
> &nbsp;&nbsp;# debug info  
> &nbsp;&nbsp;puts "\n" + "="\*10 + "DBG", line, "="\*10+ "DBG\n"
> 
> &nbsp;&nbsp;# 1) collect everything (not greedy) until first letter  
> &nbsp;&nbsp;if line =~ /^ (.\*?) [a-zA-Z] /x
> 
> &nbsp;&nbsp;&nbsp;&nbsp;prefix = $1  
> &nbsp;&nbsp;&nbsp;&nbsp;puts "prefix= '#{prefix}'"
> 
> &nbsp;&nbsp;&nbsp;&nbsp;# 2) validate format: numbers separated by digits  
> &nbsp;&nbsp;&nbsp;&nbsp;if prefix =~ /^ (?:\d+ [.]?)+ $ /x
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# 3) collect the numbers in an array  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr = prefix.split('.')
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# 4) verify max array size  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts " (Error: depth of hierarchy \> #{MLN}!)" if  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr.length \> MLN
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# 5) any number begins with 0?  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts " (Error: a nr begins with 0!) " if  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr.any? { |v| v =~ /^0/ }
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print " Numbers: ", arr.join(', '), "\n"
> 
> &nbsp;&nbsp;&nbsp;&nbsp;else  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;raise FormatError, "Prefix format NOT nr.nr.nr.."  
> &nbsp;&nbsp;&nbsp;&nbsp;end
> 
> &nbsp;&nbsp;else  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "the line has no prefix (option or error?)"  
> &nbsp;&nbsp;end
> 
> end # input
> 
> This program generated, tested with the same data you used, this output:
> 
> ==========DBG  
> 05Topic 5  
> ==========DBG  
> prefix= '05'  
> &nbsp;&nbsp;(Error: a nr begins with 0!)  
> &nbsp;&nbsp;Numbers: 05
> 
> ==========DBG  
> 1Topic 1  
> ==========DBG  
> prefix= '1'  
> &nbsp;&nbsp;Numbers: 1
> 
> ==========DBG  
> 2.002.1Topic 2.2.1  
> ==========DBG  
> prefix= '2.002.1'  
> &nbsp;&nbsp;(Error: depth of hierarchy \> 2!)  
> &nbsp;&nbsp;(Error: a nr begins with 0!)  
> &nbsp;&nbsp;Numbers: 2, 002, 1
> 
> ==========DBG  
> 2.1Topic 2.1  
> ==========DBG  
> prefix= '2.1'  
> &nbsp;&nbsp;Numbers: 2, 1
> 
> ==========DBG  
> 2.2.02Topic 2.2.2  
> ==========DBG  
> prefix= '2.2.02'  
> &nbsp;&nbsp;(Error: depth of hierarchy \> 2!)  
> &nbsp;&nbsp;(Error: a nr begins with 0!)  
> &nbsp;&nbsp;Numbers: 2, 2, 02
> 
> As you can see, it seems to work well (it also catches double errors,  
> which is nice). Notice that if the max array size had to be changed, we  
> just need to modify the MLN value.
> 
> I hope this made sense, and that it helped.  
> Good luck!
> 
> Raul  
> --  
> Posted viahttp://www.ruby-forum.com/.

Hi Raul,

Thanks for your response.

I like your "battle plan". It works well for your exposition here. I  
always have to prepare a high-level one when I propose a software  
solution to a user.

Harry posted a succinct illustration of applying Ruby to this kind of  
validation, which I appreciated. I also appreciate your slightly  
longer approach because I need this structure  
so that I can make use of data for my purpose beyond validation.

I especially appreciate your showing me how a regex can be written to  
handle an arbitrary number of dot-separated numbers (rather than hard-  
code distinct sub-expressions).

> &nbsp;&nbsp;if line =~ /^ (.\*?) [a-zA-Z] /x

I have one question about this regex. I have a book that I bought in  
2002 but never read until today: "Mastering Regular Expressions", 2nd  
Ed., from O'Reilly. I haven't been able to find any reference in  
there to a question-mark following ".\*".

I thought I could simply remove the question-mark. That caused the  
match to fail and yield the programmed error msg. I tried omitting  
the question-mark and add a closing "$" in the regex. That made the  
parsing fail. So, your question mark is clearly working, but HOW?

I'm fully on board with the rest of your code. Many thanks for it  
all!

Regards,  
Richard

> **···**
>
> On Nov 19, 5:47 am, Raul Parolari \<raulparol...@gmail.com\> wrote:

---

<div class="post-metadata">

**Author:** ![Richard3](https://avatars.discourse-cdn.com/v4/letter/r/b5a626/32.png) [@Richard3](https://rubytalk.org/u/Richard3)\
**Post date:** [20 November 2007 02:05 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312/7 "2007-11-20T02:05:01Z")

</div>

> \> Problem solved!
> 
> \> I went through a convoluted process to determine whether any of the  
> \> initial numbers began with a zero. I simplified it to:
> 
> \> i\_thNumberHasLeadingZero = (n[i] =~ /^0+/) ? true : false
> 
> \> I apologize for raising the question. My excuse is that I was  
> \> flailing about unable to figure out what was wrong. After I posted,  
> \> I took a harder look and realized my big mistake: I needed to use the  
> \> KISS method 🙂
> 
> \> Best wishes,  
> \> Richard
> 
> If you solved your problem then you won't need this.  
> But, just in case you are interested in looking at it from a little  
> different view....  
> It is not a complete solution, just an idea.
> 
> inp = \<\<DATA  
> 05Topic 5  
> 1Topic 1  
> 2.002.1Topic 2.2.1  
> 2.1Topic 2.1  
> 2.2.02Topic 2.2.2  
> DATA
> 
> err1 = inp.select{|a| a =~ /^0|\.0/}  
> puts "A number may not start with zero" unless err1.empty?  
> print err1  
> puts  
> err2 = inp.select{|b| b =~ /^\d+\.\d+\.\d/}  
> puts "No more that two numbers may be prefixed" unless err2.empty?  
> print err2
> 
> Harry
> 
> --  
> A Look into Japanese Ruby List in Englishhttp://www.kakueki.com/ruby/list.html

Hi Ryan,

> But, just in case you are interested in looking at it from a little  
> different view....  
> It is not a complete solution, just an idea.

I AM interested, and it's a great idea. Real Ruby rather than my C-  
flavored Ruby 🙂

Just for our mutual amusement, I replaced your first criterion:

err1 = inp.select{|a| a =~ /^0|\.0/}

with:

err1 = inp.select{|a| a =~ /^0|^\d\*\.0/}

to preclude false hits where the text proper might contain ".0", e.g.,  
"7How to get 5.05% interest"

Bottom line: Your code is what I really need. Thanks, again.

Best wishes,  
Richard

> **···**
>
> On Nov 19, 2:42 am, Harry Kakueki \<list.p...@gmail.com\> wrote:

---

<div class="post-metadata">

**Author:** ![Richard3](https://avatars.discourse-cdn.com/v4/letter/r/b5a626/32.png) [@Richard3](https://rubytalk.org/u/Richard3)\
**Post date:** [21 November 2007 02:35 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312/8 "2007-11-21T02:35:02Z")

</div>

> I realize you solved your problem, but there is a much more insidious  
> underlying issues here:
> 
> \>\> MLN = 2 # MaxLeadingNumbers
> 
> MLN
> 
> \>\> sName =~ /^([\d]+)?\.?([\d]+)?\.?([\d]+)?\.?/
> 
> sName
> 
> \>\> n = Array.new
> 
> n
> 
> \>\> print "DBG0\>\> "; (1..MLN+1).each { |i|  
> \>\> printf("\t#{n[i]}") };
> 
> nasty compounded lines and obtuse debugging output
> 
> \>\> i\_thNumberExists = n[i] ? true : false  
> \>\> iThNumbrerHasLeadingZero = i\_thNumberExists &&
> 
> i\_thNumberExists  
> iThNumbrerHasLeadingZero
> 
> ARGH! My eyes! STOP!!!
> 
> Ruby is NOT C.
> 
> For the love of all that is ruby, please write readable code!
> 
> Use English variable names (or whatever your native language is--just  
> use words). Don't use hungarian notation, it doesn't help--hell, your  
> variable names are so ugly you can't even read the misspellings in  
> them. Don't mix camelcase and underscores. Don't use 'n[i] ? true :  
> false' when 'n[i]' would do. Don't debug with logging. Write tests. /  
> [\d]+/ is the same as /\d+/. Those evals are TERRIFYING. Don't use them.
> 
> And, most importantly, 2 spaces per indent.
> 
> If you follow these suggestions, your code will be much more  
> understandable and less error prone. Really.

Hi Ryan,

Thanks for taking the trouble to critique my code. Since you were  
kind enough to take a thorough look at the code and offer detailed  
comments, I feel obligated to address each issue you raised.

I agree with some of your responses, don't understand some, and  
suspect some are merely a matter of taste. I'm going to tackle them  
one-by-one, but I especially want to thank you for suggesting Unit  
Test in Ruby, which I haven't used yet (and don't immediately see how  
I'd apply them).

> \>\> MLN = 2 # MaxLeadingNumbers
> 
> MLN

Are you suggesting that rather than using an abbreviation for  
MaxLeadingNumbers, I should use the longer string? If so, don't you  
think that would create unnecessary clutter? Is this more than a  
matter of personal taste?

> \>\> sName =~ /^([\d]+)?\.?([\d]+)?\.?([\d]+)?\.?/
> 
> sName

Did you draw attention to this because of the Hungarian notation? If  
so, do you think I'm unwise to adopt the style once advocated by  
Charles Simoni, super-programmer and co-founder of a giant software  
company?

> \>\> n = Array.new
> 
> n
> 
> \>\> print "DBG0\>\> "; (1..MLN+1).each { |i|  
> \>\> printf("\t#{n[i]}") };
> 
> nasty compounded lines and obtuse debugging output

There was one more piece of that line that got cut off somehow:  
"puts". If we get aside from the tracing issue for a moment, don't  
you think it's better to have one-liner debugging statements that can  
be easily deleted later, rather than multi-line statements where  
something might be overlooked when deleting them later?

> \>\> i\_thNumberExists = n[i] ? true : false  
> \>\> iThNumbrerHasLeadingZero = i\_thNumberExists &&
> 
> i\_thNumberExists  
> iThNumbrerHasLeadingZero

To me, "i\_thNumberExists" reads naturally in English as "i'th Number  
Exists". I stated out with iTh ... and thought it less readable. I  
eventually replaced all instances of iTh, but posted my code before I  
completed that correction. My apologies; I agree that had I not made  
them uniform, they would provide risks of misspelling.

> Ruby is NOT C.

I'm a retired software developer with experience with a lot of  
languages, but by far the most experience with C and C++ under  
Windows. So it takes a little while to adopt the idioms of new  
language.

> Use English variable names (or whatever your native language is--just  
> use words). Don't use hungarian notation, it doesn't help  
> --hell, your  
> variable names are so ugly you can't even read the misspellings in  
> them. Don't mix camelcase and underscores.

I addressed those issues above.

> Don't use 'n[i] ? true : false'  
> when 'n[i]' would do.

Agreed. In this case, I wasn't sure that Ruby was honoring that  
equivalence, so I wanted to make it explicit.

> Don't debug with logging. Write tests.

GOOD POINT!

> /[\d]+/ is the same as /\d+/.

Thanks.

> Those evals are TERRIFYING. Don't use them.

How else can you loop through $1, $2 ... without repetitive code?

> And, most importantly, 2 spaces per indent.

Agreed. I thought I did that when I posted.

> If you follow these suggestions, your code will be much more  
> understandable and less error prone. Really.

I'll keep my fingers crossed 🙂

Regards,  
Richard

> **···**
>
> On Nov 19, 2:23 am, Ryan Davis \<ryand-r...@zenspider.com\> wrote:
> 
> > On Nov 18, 2007, at 22:40 , RichardOnRails wrote:

---

<div class="post-metadata">

**Author:** ![yermej](https://avatars.discourse-cdn.com/v4/letter/y/b2d939/32.png) [@yermej](https://rubytalk.org/u/yermej)\
**Post date:** [22 November 2007 02:55 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312/9 "2007-11-22T02:55:00Z")

</div>

I can help with this one. Check "Mastering Regular Expressions" for  
non-greedy operators. Normally, ".\*" will match everything it possibly  
can. Adding the "?" causes it to do a minimal match -- it will match  
as little as necessary to still fill the requirements. In the above  
case, it matches everything until the first letter. Without the "?" it  
matches everything until the last letter.

Jeremy

> **···**
>
> On Nov 20, 8:00 pm, RichardOnRails \<RichardDummyMailbox58...@uscomputergurus.com\> wrote:
> 
> > \> if line =~ /^ (.\*?) [a-zA-Z] /x
> > 
> > I have one question about this regex. I have a book that I bought in  
> > 2002 but never read until today: "Mastering Regular Expressions", 2nd  
> > Ed., from O'Reilly. I haven't been able to find any reference in  
> > there to a question-mark following ".\*".
> > 
> > I thought I could simply remove the question-mark. That caused the  
> > match to fail and yield the programmed error msg. I tried omitting  
> > the question-mark and add a closing "$" in the regex. That made the  
> > parsing fail. So, your question mark is clearly working, but HOW?

---

<div class="post-metadata">

**Author:** ![Raul\_Parolari](https://avatars.discourse-cdn.com/v4/letter/r/49beb7/32.png) [@Raul\_Parolari](https://rubytalk.org/u/Raul_Parolari)\
**Post date:** [22 November 2007 08:34 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312/10 "2007-11-22T08:34:34Z")

</div>

RichardOnRails wrote:

> Hi Raul,
> 
> I like your "battle plan"..  
> I especially appreciate your showing me how a regex can be written to  
> handle an arbitrary number of dot-separated numbers (rather than hard-  
> code distinct sub-expressions).
> 
> > &nbsp;&nbsp;if line =~ /^ (.\*?) [a-zA-Z] /x
> 
> I thought I could simply remove the question-mark.  
> So, your question mark is clearly working, but HOW?

Richard

I saw that Gavin has given you (in another thread) a general tutorial on  
this. I add a simpler explanation just in the context of the problem we  
treated;

&nbsp;&nbsp;.\* means 'as many characters as possible'

Now, the point 1 of the 'battle plan' was (I quote):  
"1) we first collect everything until the first letter (not included);  
we  
will consider this the Prefix."

So we want to tell the Regexp Engine: "as few characters as possible  
until you see a letter (a-zA-Z), then stop right there!".

Let's examine the 2 expressions, with and without the question mark:

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.\*?) [a-zA-Z]  
minimal nr of chars needed until .. 1st letter

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.\*) [a-zA-Z]  
as many chars you can get  
possible get away with, and then .. a letter

An example:

s="2.1Topic 2.1"

md = s.match( /^ (.\*?) [a-zA-Z] /x )  
md[1] # =\> "2.1"

md = s.match( /^ (.\*) [a-zA-Z] /x )  
md[1] # =\> "2.1Topi"

Have you seen? Both expressions were satisfied, but in different ways:  
a) the first (with .\*?) tried to find the minimal number of characters  
until the first letter, and so it stopped when it found the 'T' of  
Topic.

b) the second expression tried to find as many characters as possible,  
only bounded by having to then find a letter, so it stopped at the 'c'  
of Topic.

With sense of humour, somebody observed that ".\*? values contentment  
over greed"; and since then the ".\*?" were called "not greedy", while  
the ".\*" were called "greedy".

[I stop here as Gavin described to you '.+" & co].

One advice: the key to learn the regular expression is to read a good  
book (just trying them drives one insane) while experimenting (just  
reading drives one insane too). The time spent pays you back very  
quickly at the first serious exercise (as you can develop a  
'battle-plan' rather than a 'guerrilla war' with the regexps).

I am glad that you found the script useful, and I hope that this helped  
too

Raul

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Harry3](https://avatars.discourse-cdn.com/v4/letter/h/54ee81/32.png) [@Harry3](https://rubytalk.org/u/Harry3)\
**Post date:** [20 November 2007 15:22 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312/11 "2007-11-20T15:22:26Z")

</div>

> Hi Ryan,
> 
> \> But, just in case you are interested in looking at it from a little  
> \> different view....  
> \> It is not a complete solution, just an idea.
> 
> I AM interested, and it's a great idea. Real Ruby rather than my C-  
> flavored Ruby 🙂
> 
> Just for our mutual amusement, I replaced your first criterion:
> 
> err1 = inp.select{|a| a =~ /^0|\.0/}
> 
> with:
> 
> err1 = inp.select{|a| a =~ /^0|^\d\*\.0/}
> 
> to preclude false hits where the text proper might contain ".0", e.g.,  
> "7How to get 5.05% interest"
> 
> Bottom line: Your code is what I really need. Thanks, again.
> 
> Best wishes,  
> Richard

Yeah, you need to modify the regular expressions and whatever to fit  
your requirements.  
Like I said, it's not a complete solution, just an idea you can use.

By the way, stop calling me Shirley. 🙂  
And stop calling me Ryan. 🙂

Good luck,

Harry

> **···**
>
> --  
> A Look into Japanese Ruby List in English
> 
> > **[Kakueki.com is for sale | HugeDomains](https://www.hugedomains.com/domain_profile.cfm?d=kakueki.com)**
> >
> > Start using this domain right away. Straightforward domain shopping experience. Quick access to your domain.

---

<div class="post-metadata">

**Author:** ![Clifford\_Heath5](https://avatars.discourse-cdn.com/v4/letter/c/7ab992/32.png) [@Clifford\_Heath5](https://rubytalk.org/u/Clifford_Heath5)\
**Post date:** [21 November 2007 17:40 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312/12 "2007-11-21T17:40:01Z")

</div>

RichardOnRails wrote:

> > > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sName =~ /^([\d]+)?\.?([\d]+)?\.?([\d]+)?\.?/
> > 
> > sName
> 
> Did you draw attention to this because of the Hungarian notation? If  
> so, do you think I'm unwise to adopt the style once advocated by  
> Charles Simoni, super-programmer and co-founder of a giant software  
> company?

Yes. Adamantly, and definitely yes.

I might have been a bad idea when he had it, even though to his  
credit he was trying to make the best of a bad situation, where  
MS had bought the worst C compiler on the planet because the good  
ones weren't for sale - they could make more money \*not\* selling  
to MS. Because of a spate of bugs and bad code churned out by the  
MS software factory, many caused by type mismatches on function  
parameters that weren't detected either at compile time or at  
runtime, Hungarian notation \*might\* have been a good idea once.

It's definitely \*not\* a good idea with modern C, and even less of  
a good idea with Ruby.

Clifford Heath.

---

<div class="post-metadata">

**Author:** ![Alex\_Young](https://avatars.discourse-cdn.com/v4/letter/a/ee7513/32.png) [@Alex\_Young](https://rubytalk.org/u/Alex_Young)\
**Post date:** [21 November 2007 18:53 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312/13 "2007-11-21T18:53:48Z")

</div>

RichardOnRails wrote:  
\<snip\>

> > Those evals are TERRIFYING. Don't use them.
> 
> How else can you loop through $1, $2 ... without repetitive code?

I don't think anyone has replied to this, so...

This is what you've got:

> &nbsp;&nbsp;sName =~ /^([\d]+)?\.?([\d]+)?\.?([\d]+)?\.?/
> 
> &nbsp;&nbsp;# Save match variables in n[1] ... n[MLN+1]  
> &nbsp;&nbsp;n = Array.new  
> &nbsp;&nbsp;(1..MLN+1).each { |i| eval %{n[i] = $#{i}} }

You can get an equivalent for n with the String#match method:

irb(main):001:0\> name = "2.2.02Topic 2.2.2"  
=\> "2.2.02Topic 2.2.2"  
irb(main):002:0\> m = name.match( /^([\d]+)?\.?([\d]+)?\.?([\d]+)?\.?/ )  
=\> #\<MatchData:0x3a3a324\>  
irb(main):003:0\> m[1]  
=\> "2"  
irb(main):004:0\> m[2]  
=\> "2"  
irb(main):005:0\> m[3]  
=\> "02"

You should be able to use that to get around your second eval, too.

> **···**
>
> > On Nov 19, 2:23 am, Ryan Davis \<ryand-r...@zenspider.com\> wrote:
> 
> --  
> Alex

---

<div class="post-metadata">

**Author:** ![Rick\_DeNatale1](https://avatars.discourse-cdn.com/v4/letter/r/bbce88/32.png) [@Rick\_DeNatale1](https://rubytalk.org/u/Rick_DeNatale1)\
**Post date:** [22 November 2007 01:44 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312/14 "2007-11-22T01:44:41Z")

</div>

Actually this form of Hungarian notation, which was called System  
Hungarian in Microsoft, is NOT what Simonyi originally sugested (and  
what was used in the Application Division).

[http://talklikeaduck.denhaven2.com/articles/2007/04/09/hungarian-ducks](http://talklikeaduck.denhaven2.com/articles/2007/04/09/hungarian-ducks)

> **···**
>
> On Nov 20, 2007 9:35 PM, RichardOnRails \<RichardDummyMailbox58407@uscomputergurus.com\> wrote:
> 
> > On Nov 19, 2:23 am, Ryan Davis \<ryand-r...@zenspider.com\> wrote:
> > 
> > \> \>\> sName =~ /^([\d]+)?\.?([\d]+)?\.?([\d]+)?\.?/  
> > \>  
> > \> sName
> > 
> > Did you draw attention to this because of the Hungarian notation? If  
> > so, do you think I'm unwise to adopt the style once advocated by  
> > Charles Simoni, super-programmer and co-founder of a giant software  
> > company?
> 
> --  
> Rick DeNatale
> 
> My blog on Ruby  
> [http://talklikeaduck.denhaven2.com/](http://talklikeaduck.denhaven2.com/)

---

<div class="post-metadata">

**Author:** ![Richard3](https://avatars.discourse-cdn.com/v4/letter/r/b5a626/32.png) [@Richard3](https://rubytalk.org/u/Richard3)\
**Post date:** [23 November 2007 16:55 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312/15 "2007-11-23T16:55:06Z")

</div>

> \> \> if line =~ /^ (.\*?) [a-zA-Z] /x
> 
> \> I have one question about this regex. I have a book that I bought in  
> \> 2002 but never read until today: "Mastering Regular Expressions", 2nd  
> \> Ed., from O'Reilly. I haven't been able to find any reference in  
> \> there to a question-mark following ".\*".
> 
> \> I thought I could simply remove the question-mark. That caused the  
> \> match to fail and yield the programmed error msg. I tried omitting  
> \> the question-mark and add a closing "$" in the regex. That made the  
> \> parsing fail. So, your question mark is clearly working, but HOW?
> 
> I can help with this one. Check "Mastering Regular Expressions" for  
> non-greedy operators. Normally, ".\*" will match everything it possibly  
> can. Adding the "?" causes it to do a minimal match -- it will match  
> as little as necessary to still fill the requirements. In the above  
> case, it matches everything until the first letter. Without the "?" it  
> matches everything until the last letter.
> 
> Jeremy

Hi Jeremy,

> non-greedy operators.

Thanks for that detailed explanation. I tried Googling for "(.\*?)  
regular expression", but Google thiks it's too weird to actutally  
include "(.\*?)" in a search ... and I don;t blame them. I checed  
Amazon to see if there is a later edition of "Masttering ...", to no  
avail.

Again, thanks for taking the time to respond.

Regards,  
Richard

> **···**
>
> On Nov 21, 9:51 pm, yermej \<yer...@gmail.com\> wrote:
> 
> > On Nov 20, 8:00 pm, RichardOnRails \> \> \<RichardDummyMailbox58...@uscomputergurus.com\> wrote:

---

<div class="post-metadata">

**Author:** ![Richard3](https://avatars.discourse-cdn.com/v4/letter/r/b5a626/32.png) [@Richard3](https://rubytalk.org/u/Richard3)\
**Post date:** [24 November 2007 19:20 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312/16 "2007-11-24T19:20:02Z")

</div>

> RichardOnRails wrote:  
> \> Hi Raul,
> 
> \> I like your "battle plan"..  
> \> I especially appreciate your showing me how a regex can be written to  
> \> handle an arbitrary number of dot-separated numbers (rather than hard-  
> \> code distinct sub-expressions).
> 
> \>\> if line =~ /^ (.\*?) [a-zA-Z] /x
> 
> \> I thought I could simply remove the question-mark.  
> \> So, your question mark is clearly working, but HOW?
> 
> Richard
> 
> I saw that Gavin has given you (in another thread) a general tutorial on  
> this. I add a simpler explanation just in the context of the problem we  
> treated;
> 
> &nbsp;&nbsp;.\* means 'as many characters as possible'
> 
> Now, the point 1 of the 'battle plan' was (I quote):  
> "1) we first collect everything until the first letter (not included);  
> we  
> will consider this the Prefix."
> 
> So we want to tell the Regexp Engine: "as few characters as possible  
> until you see a letter (a-zA-Z), then stop right there!".
> 
> Let's examine the 2 expressions, with and without the question mark:
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.\*?) [a-zA-Z]  
> minimal nr of chars needed until .. 1st letter
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.\*) [a-zA-Z]  
> as many chars you can get  
> possible get away with, and then .. a letter
> 
> An example:
> 
> s="2.1Topic 2.1"
> 
> md = s.match( /^ (.\*?) [a-zA-Z] /x )  
> md[1] # =\> "2.1"
> 
> md = s.match( /^ (.\*) [a-zA-Z] /x )  
> md[1] # =\> "2.1Topi"
> 
> Have you seen? Both expressions were satisfied, but in different ways:  
> a) the first (with .\*?) tried to find the minimal number of characters  
> until the first letter, and so it stopped when it found the 'T' of  
> Topic.
> 
> b) the second expression tried to find as many characters as possible,  
> only bounded by having to then find a letter, so it stopped at the 'c'  
> of Topic.
> 
> With sense of humour, somebody observed that ".\*? values contentment  
> over greed"; and since then the ".\*?" were called "not greedy", while  
> the ".\*" were called "greedy".
> 
> [I stop here as Gavin described to you '.+" & co].
> 
> One advice: the key to learn the regular expression is to read a good  
> book (just trying them drives one insane) while experimenting (just  
> reading drives one insane too). The time spent pays you back very  
> quickly at the first serious exercise (as you can develop a  
> 'battle-plan' rather than a 'guerrilla war' with the regexps).
> 
> I am glad that you found the script useful, and I hope that this helped  
> too
> 
> Raul  
> --  
> Posted viahttp://www.ruby-forum.com/.

Hi Raul,

Thank you very much for your expanded analysis.

> I saw that Gavin has given you (in another thread) ...

I started a new thread on the "(.\*?)" because this thread was getting  
too long. And Gavin tuning me on to "greedy" was a big boost. That  
let me find some relevant stuff in "Mastering Reglar Expressions, 2nd  
ed."

> An example: ...

Your example is great. I went back to Hal Fulton's "The Ruby Way, 2nd  
ed." and [class Regexp - RDoc Documentation](http://www.ruby-doc.org/core/classes/Regexp.html) for  
additional Regexp#match documentation.

Not withstanding your exposition and the documentation cited, my  
reptilian brain refuses acceptance on this issue. But by running the  
examples given and some of my own construction, I should get over  
this hump. (I wrote my own NFSA in C for a client's application  
roughly 30 year's ago, so I should be equal to the task.)

I'm not going expose my ignorance with any further questions on this  
matter. I'll do my homework 🙂

With thanks and best wishes,  
Richard

> **···**
>
> On Nov 22, 3:34 am, Raul Parolari \<raulparol...@gmail.com\> wrote:

---

<div class="post-metadata">

**Author:** ![Richard3](https://avatars.discourse-cdn.com/v4/letter/r/b5a626/32.png) [@Richard3](https://rubytalk.org/u/Richard3)\
**Post date:** [26 November 2007 22:25 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312/17 "2007-11-26T22:25:01Z")

</div>

> RichardOnRails wrote:  
> \> Hi Raul,
> 
> \> I like your "battle plan"..  
> \> I especially appreciate your showing me how a regex can be written to  
> \> handle an arbitrary number of dot-separated numbers (rather than hard-  
> \> code distinct sub-expressions).
> 
> \>\> if line =~ /^ (.\*?) [a-zA-Z] /x
> 
> \> I thought I could simply remove the question-mark.  
> \> So, your question mark is clearly working, but HOW?
> 
> Richard
> 
> I saw that Gavin has given you (in another thread) a general tutorial on  
> this. I add a simpler explanation just in the context of the problem we  
> treated;
> 
> &nbsp;&nbsp;.\* means 'as many characters as possible'
> 
> Now, the point 1 of the 'battle plan' was (I quote):  
> "1) we first collect everything until the first letter (not included);  
> we  
> will consider this the Prefix."
> 
> So we want to tell the Regexp Engine: "as few characters as possible  
> until you see a letter (a-zA-Z), then stop right there!".
> 
> Let's examine the 2 expressions, with and without the question mark:
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.\*?) [a-zA-Z]  
> minimal nr of chars needed until .. 1st letter
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.\*) [a-zA-Z]  
> as many chars you can get  
> possible get away with, and then .. a letter
> 
> An example:
> 
> s="2.1Topic 2.1"
> 
> md = s.match( /^ (.\*?) [a-zA-Z] /x )  
> md[1] # =\> "2.1"
> 
> md = s.match( /^ (.\*) [a-zA-Z] /x )  
> md[1] # =\> "2.1Topi"
> 
> Have you seen? Both expressions were satisfied, but in different ways:  
> a) the first (with .\*?) tried to find the minimal number of characters  
> until the first letter, and so it stopped when it found the 'T' of  
> Topic.
> 
> b) the second expression tried to find as many characters as possible,  
> only bounded by having to then find a letter, so it stopped at the 'c'  
> of Topic.
> 
> With sense of humour, somebody observed that ".\*? values contentment  
> over greed"; and since then the ".\*?" were called "not greedy", while  
> the ".\*" were called "greedy".
> 
> [I stop here as Gavin described to you '.+" & co].
> 
> One advice: the key to learn the regular expression is to read a good  
> book (just trying them drives one insane) while experimenting (just  
> reading drives one insane too). The time spent pays you back very  
> quickly at the first serious exercise (as you can develop a  
> 'battle-plan' rather than a 'guerrilla war' with the regexps).
> 
> I am glad that you found the script useful, and I hope that this helped  
> too
> 
> Raul  
> --  
> Posted viahttp://www.ruby-forum.com/.

Hi Raul,

> read a good book (just trying them drives one insane)  
> while experimenting

I certainly agree with regard to REs. And I've got "Mastering Regular  
Expressions, vol. 2" by Friedl.

> (just reading drives one insane too).

Well, they haven't carted me off yet 🙂

As I've said, your approach works great. But I do want to  
experiment, too. So I tried the following, and I'm hopeful that you  
can tolerate another question:

Program

> **···**
>
> On Nov 22, 3:34 am, Raul Parolari \<raulparol...@gmail.com\> wrote:  
> -------  
> input = \<\<DATA  
> 05Topic 5  
> 2.002.1Topic 2.2.1  
> DATA
> 
> input.each do |line|  
> &nbsp;&nbsp;line =~ /^ (\d+[\.]?)+ [^\.\d] /x #  
> &nbsp;&nbsp;puts line  
> &nbsp;&nbsp;puts $1, $2  
> &nbsp;&nbsp;puts  
> end
> 
> Output  
> ------  
> 05Topic 5  
> 05  
> nil
> 
> 2.002.1Topic 2.2.1  
> 1  
> nil
> 
> Question  
> --------  
> I'm puzzled by "1" in the second output, because the "^" in the RE  
> specifies that a match must occur at the first character. I expected  
> to get $1=2, at least, and hopefully $2=002 and %3=1, though I was  
> willing to work on the last two items.
> 
> Am I wrong about the caret?

---

<div class="post-metadata">

**Author:** ![Richard3](https://avatars.discourse-cdn.com/v4/letter/r/b5a626/32.png) [@Richard3](https://rubytalk.org/u/Richard3)\
**Post date:** [26 November 2007 23:30 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312/18 "2007-11-26T23:30:00Z")

</div>

> RichardOnRails wrote:  
> \> Hi Raul,
> 
> \> I like your "battle plan"..  
> \> I especially appreciate your showing me how a regex can be written to  
> \> handle an arbitrary number of dot-separated numbers (rather than hard-  
> \> code distinct sub-expressions).
> 
> \>\> if line =~ /^ (.\*?) [a-zA-Z] /x
> 
> \> I thought I could simply remove the question-mark.  
> \> So, your question mark is clearly working, but HOW?
> 
> Richard
> 
> I saw that Gavin has given you (in another thread) a general tutorial on  
> this. I add a simpler explanation just in the context of the problem we  
> treated;
> 
> &nbsp;&nbsp;.\* means 'as many characters as possible'
> 
> Now, the point 1 of the 'battle plan' was (I quote):  
> "1) we first collect everything until the first letter (not included);  
> we  
> will consider this the Prefix."
> 
> So we want to tell the Regexp Engine: "as few characters as possible  
> until you see a letter (a-zA-Z), then stop right there!".
> 
> Let's examine the 2 expressions, with and without the question mark:
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.\*?) [a-zA-Z]  
> minimal nr of chars needed until .. 1st letter
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.\*) [a-zA-Z]  
> as many chars you can get  
> possible get away with, and then .. a letter
> 
> An example:
> 
> s="2.1Topic 2.1"
> 
> md = s.match( /^ (.\*?) [a-zA-Z] /x )  
> md[1] # =\> "2.1"
> 
> md = s.match( /^ (.\*) [a-zA-Z] /x )  
> md[1] # =\> "2.1Topi"
> 
> Have you seen? Both expressions were satisfied, but in different ways:  
> a) the first (with .\*?) tried to find the minimal number of characters  
> until the first letter, and so it stopped when it found the 'T' of  
> Topic.
> 
> b) the second expression tried to find as many characters as possible,  
> only bounded by having to then find a letter, so it stopped at the 'c'  
> of Topic.
> 
> With sense of humour, somebody observed that ".\*? values contentment  
> over greed"; and since then the ".\*?" were called "not greedy", while  
> the ".\*" were called "greedy".
> 
> [I stop here as Gavin described to you '.+" & co].
> 
> One advice: the key to learn the regular expression is to read a good  
> book (just trying them drives one insane) while experimenting (just  
> reading drives one insane too). The time spent pays you back very  
> quickly at the first serious exercise (as you can develop a  
> 'battle-plan' rather than a 'guerrilla war' with the regexps).
> 
> I am glad that you found the script useful, and I hope that this helped  
> too
> 
> Raul  
> --  
> Posted viahttp://www.ruby-forum.com/.

Hi Raul,

I forgot to tell you that I finally understand your second example.

> md = s.match( /^ (.\*) [a-zA-Z] /x )  
> md[1] # =\> "2.1Topi"

Without the question mark, in principal, the ".\* initially consumes  
all the characters, but then it sees the match fails, because there's  
no match for the "[a-zA-Z]". So the ".\*" sort of "backs off" and  
satisfies it self with "2.1Topi", leaving the "c" to satisfy "[a-zA-  
Z]".

Cool. Actually, I read that in "Mastering Regular Expressions, vol.  
2", but it really didn't settle into my WeltAnshaung. But I think I  
got it now!

Furthermore, the "non-greedy question mark" says "consume only as much  
as you need in order to satisfy the total RE. So "(.\*?) needs to  
consumed all the caracters up to something satisfying the "[a-zA-Z]",  
which is the "T"

The one I like settled on is:

s="2.1Topic 2.1"  
md = s.match( /^ ([\.\d]\*) [^\.\d] /x )  
&nbsp;&nbsp;#md[0]=2.1T  
&nbsp;&nbsp;#md[1]=2.1

> **···**
>
> On Nov 22, 3:34 am, Raul Parolari \<raulparol...@gmail.com\> wrote:

---

<div class="post-metadata">

**Author:** ![Richard3](https://avatars.discourse-cdn.com/v4/letter/r/b5a626/32.png) [@Richard3](https://rubytalk.org/u/Richard3)\
**Post date:** [21 November 2007 01:20 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312/19 "2007-11-21T01:20:05Z")

</div>

Hi H

> **···**
>
> On Nov 20, 10:22 am, Harry Kakueki \<list.p...@gmail.com\> wrote:
> 
> > \> Hi Ryan,
> > 
> > \> \> But, just in case you are interested in looking at it from a little  
> > \> \> different view....  
> > \> \> It is not a complete solution, just an idea.
> > 
> > \> I AM interested, and it's a great idea. Real Ruby rather than my C-  
> > \> flavored Ruby 🙂
> > 
> > \> Just for our mutual amusement, I replaced your first criterion:
> > 
> > \> err1 = inp.select{|a| a =~ /^0|\.0/}
> > 
> > \> with:
> > 
> > \> err1 = inp.select{|a| a =~ /^0|^\d\*\.0/}
> > 
> > \> to preclude false hits where the text proper might contain ".0", e.g.,  
> > \> "7How to get 5.05% interest"
> > 
> > \> Bottom line: Your code is what I really need. Thanks, again.
> > 
> > \> Best wishes,  
> > \> Richard
> > 
> > Yeah, you need to modify the regular expressions and whatever to fit  
> > your requirements.  
> > Like I said, it's not a complete solution, just an idea you can use.
> > 
> > By the way, stop calling me Shirley. 🙂  
> > And stop calling me Ryan. 🙂
> > 
> > Good luck,
> > 
> > Harry
> > 
> > --  
> > A Look into Japanese Ruby List in Englishhttp://www.kakueki.com/ruby/list.html

---

<div class="post-metadata">

**Author:** ![Richard3](https://avatars.discourse-cdn.com/v4/letter/r/b5a626/32.png) [@Richard3](https://rubytalk.org/u/Richard3)\
**Post date:** [21 November 2007 01:24 UTC](https://rubytalk.org/t/false-positives-in-editing-data/42312/20 "2007-11-21T01:24:59Z")

</div>

> \> Hi Ryan,
> 
> \> \> But, just in case you are interested in looking at it from a little  
> \> \> different view....  
> \> \> It is not a complete solution, just an idea.
> 
> \> I AM interested, and it's a great idea. Real Ruby rather than my C-  
> \> flavored Ruby 🙂
> 
> \> Just for our mutual amusement, I replaced your first criterion:
> 
> \> err1 = inp.select{|a| a =~ /^0|\.0/}
> 
> \> with:
> 
> \> err1 = inp.select{|a| a =~ /^0|^\d\*\.0/}
> 
> \> to preclude false hits where the text proper might contain ".0", e.g.,  
> \> "7How to get 5.05% interest"
> 
> \> Bottom line: Your code is what I really need. Thanks, again.
> 
> \> Best wishes,  
> \> Richard
> 
> Yeah, you need to modify the regular expressions and whatever to fit  
> your requirements.  
> Like I said, it's not a complete solution, just an idea you can use.
> 
> By the way, stop calling me Shirley. 🙂  
> And stop calling me Ryan. 🙂
> 
> Good luck,
> 
> Harry
> 
> --  
> A Look into Japanese Ruby List in Englishhttp://www.kakueki.com/ruby/list.html

Hi Harry,

I apologize for the "Ryan" thing. Ryan was the first response on this  
thread and got mixed up. I don't know about the "Shirley" thing.

I don't know what's going on there, but I apologize again for any way  
I might have erred.

And I fear I owe you a third apology: I minute ago, I started to  
reply to your most recent post when I stopped getting a timely  
response to my typing. I continue to type, assuming my ISP would  
catch up sooner or later and hit Enter. Suddenly, I got a message  
that my half-baked response had been posted. Computers: uggggh!

> Like I said, it's not a complete solution, just an idea you can use.

I know. I just wanted to show you I was giving my full attention to  
your message.

Again, thanks for showing how Ruby can be used more effectively for  
this kind of validation task.

Best wishes,  
Richard

> **···**
>
> On Nov 20, 10:22 am, Harry Kakueki \<list.p...@gmail.com\> wrote:

[Next page](https://rubytalk.org/t/false-positives-in-editing-data/42312.md?page=2)
