return number of spaces at the beginning of a line

J

Jesse B.

How would I find the number of spaces at the beginning of a line before
the occurrance of the first non-space character?

Would the best method be to use a regular expression that covers all
non-space characters and get the index of the first occurrance of that?
 
J

jbw

[Note: parts of this message were removed to make it a legal post.]

How would I find the number of spaces at the beginning of a line before
the occurrance of the first non-space character?

Would the best method be to use a regular expression that covers all
non-space characters and get the index of the first occurrance of that?
You could use regex you could also, if the data is a string or an array,
split them into a char array

e.g. :
s = " hello"
s = s.chars.to_a
=> [" ", " ", " ", " ", "h", "e", "l", "l", "o"]

s.each do | c |
if( c == " " )
i = i+1
puts i
end
end

and that'll count the number of spaces.
 
H

Harry Kakueki

How would I find the number of spaces at the beginning of a line before
the occurrance of the first non-space character?

Would the best method be to use a regular expression that covers all
non-space characters and get the index of the first occurrance of that?
--

If I understand your question correctly,

str = " hello"
p str =~ /\S/


Harry
 
G

Gennady Bystritsky

How would I find the number of spaces at the beginning of a line before
the occurrance of the first non-space character?
=20
Would the best method be to use a regular expression that covers all
non-space characters and get the index of the first occurrance of that?
--=20
Posted via http://www.ruby-forum.com/.

s =3D " abc"
s.index(%r{\S}) # =3D> 3

s.scan(%r{^\s*}).first.size # =3D> 3

Gennady.
 
S

Steve Howell

How would I find the number of spaces at the beginning of a line before
the occurrance of the first non-space character?

Would the best method be to use a regular expression that covers all
non-space characters and get the index of the first occurrance of that?

I think the following expresses what you are trying to do, but I do
not know if this is the most efficient or idiomatic way to do it:

def num_leading_spaces(s)
prefix = (s =~ /(\s*)/)
$1.length
end

puts num_leading_spaces(' hello')
 
S

Steve Howell

I think the following expresses what you are trying to do, but I do
not know if this is the most efficient or idiomatic way to do it:

    def num_leading_spaces(s)
      prefix = (s =~ /(\s*)/)
      $1.length
    end

    puts num_leading_spaces('   hello')

Oops, still not sure whether this is ideal, but this is better than my
other version:

def num_leading_spaces(s)
s =~ /(\s*)/
$1.length
end
 
R

Robert Klemme

2010/3/30 Jesse B. said:
How would I find the number of spaces at the beginning of a line before
the occurrance of the first non-space character?

spaces = str[/\A\s*/].length
Would the best method be to use a regular expression that covers all
non-space characters and get the index of the first occurrance of that?

I'd rather use the approach above because it always works (i.e. even
with empty strings). Your approach could be done like this:

spaces = /\S/ =~ s

as has been show already. But this fails for empty strings.

Kind regards

robert
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

How would I find the number of spaces at the beginning of a line before
the occurrance of the first non-space character?

Would the best method be to use a regular expression that covers all
non-space characters and get the index of the first occurrance of that?
Hi, a quick appraisal of the issues with previous solutions.


This solution counts non-leading spaces
i = 0
" hello ".chars.to_a.each do |c|
i+=1 if( c == " " )
end


This one returns nil if there is not text after the leading whitespaces.
str =~ /\S/


Each of these count non-space whitespaces (ie " \t hello" would be 3 instead
of 1 )
s.index(%r{\S})

str[/\A\s*/].length

s =~ /(\s*)/
$1.length



So here is a quick suite you can use to test the solutions, along with a
solution which passes. If this suite doesn't accurately reflect what you
were trying to do, modify it and re-post :) You'll be a lot more likely to
get a solution which does explicitly what you are looking for, and maybe
find some areas that are ambiguous in your question, such as multi-line
strings, and strings with mixtures of whitespace types.

require 'test/unit'

def leading_spaces( str )
# fill this out however you like, my solution is:
str =~ /[^ ]/ || str.length
end

class TestLeadingSpaces < Test::Unit::TestCase

def test_one_space
assert_equal 1 , leading_spaces(' ')
end

def test_empty_string
assert_equal 0 , leading_spaces('')
end

def test_two_leading_spaces
assert_equal 2 , leading_spaces(' hello')
end

def test_no_spaces
assert_equal 0 , leading_spaces('hello')
end

def test_spaces_inside_but_not_leading
assert_equal 0 , leading_spaces('hello there')
end

def test_spaces_inside_and_leading
assert_equal 2 , leading_spaces(' hello there')
end

def test_trailing_spaces_not_leading
assert_equal 0 , leading_spaces('hello ')
end

def test_trailing_spaces_and_inside
assert_equal 0 , leading_spaces('hello there ')
end

def test_spaces_everywhere
assert_equal 1 , leading_spaces(' hello there ')
end

def test_mixture_of_spaces_and_tabs
assert_equal 1 , leading_spaces(" \t hello")
end

# the following are not really defined in the question, this is what I
think the OP is asking for
# might also be asking for an array listing the indentions for each line?
def multi_line_spaces
assert_equal 6 , leading_spaces(<<-MULTI_LINE_STRING)
this is six spaces
this is eight
MULTI_LINE_STRING
end
end
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

Two things:
1) The name of the method multi_line_spaces won't actually test, because
TestUnit only considers a method to be a test if it begins with 'test' so
you should change it's name to test_multi_line_spaces

2) I thought of another test you should add. Throwing wholly bad data at it.
In this case, nil
def test_nil
assert_raises NoMethodError do
leading_spaces nil
end
end

'The Pragmatic Programmer' says that it is better to crash early, so I
tested that it should throw an error.

You might also consider what you would like it to do in the event that you
pass it something not a string. Perhaps invoke the to_s method and then get
the length of the leading whitespace. Perhaps raise a different error.
 
R

Robert Klemme

Hi, a quick appraisal of the issues with previous solutions.
Each of these count non-space whitespaces (ie " \t hello" would be 3 instead
of 1 )
s.index(%r{\S})

str[/\A\s*/].length

s =~ /(\s*)/
$1.length

Oh, that's easily fixed: just replace \s with ' ' e.g. s[\A */].length
(still my favorite). I thought general whitespace was sought after.

Kind regards

robert
 
J

Jesse B.

This second post with the "spaces only" fix seems to meet all the needs
of what I was looking for.

I love that this got 9 replies in the middle of the night.
thanks everyone for your help.

Robert said:
Hi, a quick appraisal of the issues with previous solutions.
Each of these count non-space whitespaces (ie " \t hello" would be 3 instead
of 1 )
s.index(%r{\S})

str[/\A\s*/].length

s =~ /(\s*)/
$1.length

Oh, that's easily fixed: just replace \s with ' ' e.g. s[\A */].length
(still my favorite). I thought general whitespace was sought after.

Kind regards

robert
 
R

Robert Klemme

2010/3/30 Jesse B. said:
This second post with the "spaces only" fix seems to meet all the needs
of what I was looking for.

I love that this got 9 replies in the middle of the night.
thanks everyone for your help.

What do you mean, middle of the night? It's quite sunny here and the
sun isn't even going to settle soon. ;-)

Cheers

robert
 
H

Harry Kakueki

What do you mean, middle of the night? =A0It's quite sunny here and the
sun isn't even going to settle soon. ;-)

One Bright Day In The Middle Of The Night. :)




Harry
 
C

Colin Bartlett

What do you mean, middle of the night? =A0It's quite sunny here and the
sun isn't even going to settle soon. ;-)

robert
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Well, it's also nowhere near the middle of the night here
(n*100 kilometres west of Robert?, where 0 < n < 13?)
but it's definitely not "quite sunny"! In fact, it's raining!
(To quote from "A Song of the Weather"
by Flanders and Swann - 1950s/1960s sort of English Tom Lehrer's:
April brings the sweet spring showers.
On and on for hours and hours.)

How about this? I think it's different from the other solutions(?),
it seems to work, and it doesn't create a string object(?).
(str =3D~ /[^ ]/) || str.length

def q( str )
ns =3D str =3D~ /[^ ]/ || str.length # actual code
spaces =3D str[/\A */].length # Robert's 2nd post
str.inspect.ljust(10) + " #=3D> " + ns.inspect + " =3D?=3D " + spaces.=
inspect
end

"" #=3D> 0 =3D?=3D 0
" " #=3D> 1 =3D?=3D 1
" " #=3D> 2 =3D?=3D 2
"c" #=3D> 0 =3D?=3D 0
" c" #=3D> 1 =3D?=3D 1
" c" #=3D> 2 =3D?=3D 2
" \t cc" #=3D> 1 =3D?=3D 1
 
R

Robert Klemme

2010/3/30 Colin Bartlett said:
Well, it's also nowhere near the middle of the night here
(n*100 kilometres west of Robert?, where 0 < n < 13?)

Yeah, that sounds about right.
but it's definitely not "quite sunny"! In fact, it's raining!
(To quote from "A Song of the Weather"
=A0by Flanders and Swann - 1950s/1960s sort of English Tom Lehrer's:
=A0April brings the sweet spring showers.
=A0On and on for hours and hours.)

I think I have to hurry: rain radar indicates showers coming my way.
How about this? I think it's different from the other solutions(?),
it seems to work, and it doesn't create a string object(?).
=A0(str =3D~ /[^ ]/) || str.length

I'm afraid, that is not correct; the String is created as a side
effect and stored in a global variable:

irb(main):001:0> str =3D " foo"
=3D> " foo"
irb(main):002:0> str =3D~ /[^ ]/
=3D> 3
irb(main):003:0> $&
=3D> "f"

And it has the disadvantage over str[/\A */].length that likely is
slower because of the alternative.

Kind regards

robert

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 
C

Colin Bartlett

I think I have to hurry: rain radar indicates showers coming my way.
From the west?
2010/3/30 Colin Bartlett said:
How about this? I think it's different from the other solutions(?),
it seems to work, and it doesn't create a string object(?).
=A0(str =3D~ /[^ ]/) || str.length

I'm afraid, that is not correct; the String is created as a side
effect and stored in a global variable:

irb(main):001:0> str =3D " =A0 foo" #=3D> " =A0 foo"
irb(main):002:0> str =3D~ /[^ ]/ #=3D> 3
irb(main):003:0> $& #=3D> "f"

And it has the disadvantage over str[/\A */].length that likely is
slower because of the alternative.

I'm glad that my (mathematically trained!) caution decided to add that "(?)=
".
I nearly didn't put it in, but had second thoughts!
I'd forgotten about the global variables.
I see that str.index( regexp ) also sets $&, which is nice to be reminded o=
f,
first because it might come in handy, and second because, as you point out,
side effects might make what appears to be an "elegant" solution not elegan=
t.
Well, one learns from ones mistakes!
 
R

Robert Klemme

From the west?

From south west.

http://www.wetteronline.de/dldlrad.htm
2010/3/30 Colin Bartlett said:
How about this? I think it's different from the other solutions(?),
it seems to work, and it doesn't create a string object(?).
(str =~ /[^ ]/) || str.length
I'm afraid, that is not correct; the String is created as a side
effect and stored in a global variable:

irb(main):001:0> str = " foo" #=> " foo"
irb(main):002:0> str =~ /[^ ]/ #=> 3
irb(main):003:0> $& #=> "f"

And it has the disadvantage over str[/\A */].length that likely is
slower because of the alternative.

I'm glad that my (mathematically trained!) caution decided to add that "(?)".
I nearly didn't put it in, but had second thoughts!
I'd forgotten about the global variables.
I see that str.index( regexp ) also sets $&, which is nice to be reminded of,
first because it might come in handy, and second because, as you point out,
side effects might make what appears to be an "elegant" solution not elegant.
Well, one learns from ones mistakes!

Absolutely! And there is still so much around to learn... I am still
waiting for a bit of spare time to invest in having a closer look at
PostgreSql...

Kind regards

robert
 
T

thunk

I'm impressed.

Comment: It seems amazing that even as languages get more and more
powerful, we seem to spend more time pushing strings through hoops.

I've been using '?' and '!' on the end of some methods - NOW I'm
appending things to the method names to break ties. I am converting
from sym to s, remove the /?!/ and so on and I'm rather on strange
ground exactly where my app is the most prone to serious performance
degradation. So this has been on my mind some.....

Then, following this thought I just read up on "Fancy" (shhh!) (while
reading up on new Wiki features) and was thinking about if there might
a way to use some of that for really "core" stuff.

I'm really happy with Ruby performance so far, but it could be a
factor coming up, and it seems to be a ok idea to keep an eye out for
ways to tweak performance?


Any comments on converting Symbols to Strings, doing things on them,
then converting back - is there some better way?
 
T

thunk

Adding a '+' method to Kernel for symbols would reduce code clutter
but still ultimately end up requiring conversion from symbols to
strings to do
the append operation, right?

(ruby 1.9 is allowing me to do more with the ?! chars than I think I
remember 1.8 where I think I remember getting some errors around
this. )

I would not normally care much, or feel a particular need to
understand what is going on under the hood, but I have a performance
issue right here and this happens be one of the things I'm working on.

comments?

then, what would be the best form to add two symbols together (ending
up with a symbol again)



quick check:
sym1, sym2= :abc_defg?, sym2 = :xyz
puts (sym1 + sym2).to_s
=> <main>': undefined method `+' for :abc_defg?:Symbol (NoMethodError)
 
A

Aldric Giacomoni

thunk said:
Adding a '+' method to Kernel for symbols would reduce code clutter
but still ultimately end up requiring conversion from symbols to
strings to do
the append operation, right?

(ruby 1.9 is allowing me to do more with the ?! chars than I think I
remember 1.8 where I think I remember getting some errors around
this. )

I would not normally care much, or feel a particular need to
understand what is going on under the hood, but I have a performance
issue right here and this happens be one of the things I'm working on.

comments?

then, what would be the best form to add two symbols together (ending
up with a symbol again)

You're thinking about it the wrong way. A symbol is a pointer to a
specific address in memory, kinda like a variable.
Do you expect this code to work?

a = 5
b = NeuralNetwork.new
puts (a + b).to_s

... You'll get an error, because a and b are just pointers to the
objects. Symbols are a bit different; while they are "faster" than plain
variables, or than strings, they never get garbage collected (I can not
explain any more than this, but many around here know Ruby's deep magic
well), and they always refer to the same memory space.

I think you're using symbols inappropriately. What -are- you doing with
them? If you need to add two names together, then my guess is, just
stick with strings.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,049
Latest member
Allen00Reed

Latest Threads

Top