Forum: Ruby String#capitalize more complex

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
0f1f17ba297242e9d3c86d4cc0a6ea85?d=identicon&s=25 Iñaki Baz Castillo (Guest)
on 2009-04-02 13:57
(Received via mailing list)
Hi, I receive headers (the protocol syntax allows them being lowcase,
upcase or a mix). For example, the following header names are
equivalent:

a) Record-Route
b) record-route
c) RECORD-ROUTE
d) Record-ROUTE

I'm trying to do a method to convert all of them to:

  Record-Route


Basically what I need is to capitalize all the header name parts after
splitting it using "-" as separator. I can do it as follows:

------------
hname =  "Record-ROUTE"
hname.split("-").map {|w| w.capitalize }.join("-") }  =>  "Record-Route"
------------

Benchmark.realtime { hname.split("-").map {|w| w.capitalize }.join("-")
}
1.69277191162109e-05


Is there any option even faster? I think it would be faster if I
operate directly in the original string instead of doing "split" and
"join" (since these last methods create more strings so allocate
memory for them and so). I would prefer to do the modification "in
place".

BTW, could I know how to convert "a" char into "A"? I expected
something as in c:

  'a' + 1 => 'b'
  'a' + ¿X? => 'A'

but in Ruby#String I just find String#next which just increment the
char in one unit ("a".next => "b").

Any suggestion? Thanks a lot.

Thanks a lot.
5772c599ccab3081e0fffb1d54f3b6de?d=identicon&s=25 Andrew Timberlake (andrewtimberlake)
on 2009-04-02 14:01
(Received via mailing list)
On Thu, Apr 2, 2009 at 1:55 PM, Iñaki Baz Castillo <ibc@aliax.net> wrote:
>
>
> BTW, could I know how to convert "a" char into "A"? I expected
> Thanks a lot.
>
>
> --
> Iñaki Baz Castillo
> <ibc@aliax.net>
>
>

Have a look at Net::HTTPHeader and it's code as all of this is handled
in there
http://www.ruby-doc.org/core/classes/Net/HTTPHeader.html

Andrew Timberlake
http://ramblingsonrails.com
http://www.linkedin.com/in/andrewtimberlake

"I have never let my schooling interfere with my education" - Mark Twain
0f1f17ba297242e9d3c86d4cc0a6ea85?d=identicon&s=25 Iñaki Baz Castillo (Guest)
on 2009-04-02 15:23
(Received via mailing list)
2009/4/2 Andrew Timberlake <andrew@andrewtimberlake.com>:
> Have a look at Net::HTTPHeader and it's code as all of this is handled in there
> http://www.ruby-doc.org/core/classes/Net/HTTPHeader.html

Thanks. That approach doesn't address the case I want but there are
interesting ideas.
0f1f17ba297242e9d3c86d4cc0a6ea85?d=identicon&s=25 Iñaki Baz Castillo (Guest)
on 2009-04-02 16:14
(Received via mailing list)
2009/4/2 Iñaki Baz Castillo <ibc@aliax.net>:

>  'a' + ¿X? => 'A'
I've done it in two ways:


-----------------------------
require "benchmark"


hname1 =  "record-route"
hname2 =  "record-route"

rt1=0.0
rt2=0.0


### Method 1

1.upto(10) do
  rt1 += Benchmark.realtime { hname1 = hname1.split("-").map {|w|
w.capitalize }.join("-") }
end
puts "hname1 = #{hname1}  (time = #{rt1/10})"


### Method 2

1.upto(10) do
  i=0
  rt2 += Benchmark.realtime do
    hname2.capitalize!.each_byte do |b|
      if b==45 && i<hname2.bytesize-1
        hname2[i+1] = [hname2[i+1].unpack("*c")[0] - 32].pack("*c")
      end
      i+=1
    end
  end
end
puts "hname2 = #{hname2}  (time = #{rt2/10})"
------------------------------

Results:

  hname1 = Record-Route  (time = 8.24928283691406e-06)
  hname2 = Record-Route  (time = 1.05381011962891e-05)


This is: even if method 1 uses split and join (so it generates new
strings and stores them in memory) it's faster than method 2.
Unfortunatelly method 2 also generates strings. I really wonder if
there is a nicer way to do the same in a more fast way.

Thanks.
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Thomas Sawyer (7rans)
on 2009-04-02 20:14
(Received via mailing list)
On Apr 2, 7:55 am, Iñaki Baz Castillo <i...@aliax.net> wrote:
>
> Benchmark.realtime { hname.split("-").map {|w| w.capitalize }.join("-") }
>
>   'a' + 1 => 'b'
>   'a' + ¿X? => 'A'
>
> but in Ruby#String I just find String#next which just increment the
> char in one unit ("a".next => "b").
>
> Any suggestion? Thanks a lot.
>
> Thanks a lot.

I would look at the camelcase implementations of Facets, English or
ActiveSupport. They are pretty close to what you want. You may even be
able to use one of them outright.

T.
0f1f17ba297242e9d3c86d4cc0a6ea85?d=identicon&s=25 Iñaki Baz Castillo (Guest)
on 2009-04-02 20:30
(Received via mailing list)
El Jueves 02 Abril 2009, trans
escribió:> I would look at the camelcase implementations of Facets, English or
> ActiveSupport. They are pretty close to what you want. You may even be
> able to use one of them outright.

Thanks, but finally I've decided to create a Ruby C extension for that.
The
code is very simple and fast:

---------------------

/*
 * Capitalize each word of a header name. Examples:
 * - "record-route" => "Record-Route"
 * - "from" => "From"
 * - "VIA" => "Via"
 *
 */

  char *string;
  int i;

  string = XXXXXX

  if ( string[0] >= 'a' && string[0] <= 'z' )  // 'a'=97, 'z'=122
    string[0] -= 32;

  for (i=1; i<strlen(string); i++) {
    if ( string[i-1] == '-' && string[i] >= 'a' && string[i] <= 'z' )
      string[i] -= 32;
    else if ( string[i] >= 'A' && string[i] <= 'Z' )
      string[i] += 32;
  }
This topic is locked and can not be replied to.