# Ugly code - suggestions?

**URL:** <https://www.ruby-forum.com/t/ugly-code-suggestions/74967>\
**Category:** Ruby\
**Created:** [November 7, 2006, 11:04am UTC](https://www.ruby-forum.com/t/ugly-code-suggestions/74967 "2006-11-07T11:04:25Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![ihaveguts](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/i/f05b48/32.png) [@ihaveguts](https://www.ruby-forum.com/u/ihaveguts)\
**Post date:** [November 7, 2006, 11:04am UTC](https://www.ruby-forum.com/t/ugly-code-suggestions/74967/1 "2006-11-07T11:04:25Z")

</div>

Hello!

I’m writing an ANSI color codes parser which gets a string with text  
and ANSI color codes and outputs an array with substrings and numbers  
of the color codes.  
A color code is something like “\e[31m”. Generally, I assume (am I  
wrong?) they match /\e[(\d+)(;\d+)\*m/.

Here is what I came up with:

module ANSIParser  
def self.ansi\_to\_array(str)  
str = str.to\_s  
ret = []  
while ((m = /\e[(\d+)(;\d+)\*m/.match(str)))  
ret \<\< m.pre\_match if m.pre\_match != “”  
ret += m[0].scan(/\d+/).map { |c| c.to\_i }  
str = m.post\_match  
end  
ret \<\< str if str != “”  
return ret  
end  
end

# TEST:

ansistr = “\e[31mred,\e[32;1m\e[32;1mbold green\e[33;32;31mred  
anyway, still bold\e[33;32;31m”

puts ansistr # you should see colors if your terminal supports ANSI  
escapes  
puts ANSIParser::ansi\_to\_array(ansistr).inspect

It works, but it doesn’t look much elegant. In fact, it looks much  
more like perl than ruby to me 😛  
That while over there is awful. Is there a way to make it more  
elegant? Is there some kind of iterator which does what my while  
does? If not, would you split it somehow?

I’m looking for suggestions 🙂  
Thanks!

---

<div class="post-metadata">

**Author:** ![ihaveguts](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/i/f05b48/32.png) [@ihaveguts](https://www.ruby-forum.com/u/ihaveguts)\
**Post date:** [November 7, 2006, 11:05am UTC](https://www.ruby-forum.com/t/ugly-code-suggestions/74967/2 "2006-11-07T11:05:07Z")

</div>

couple of ideas for you- didn’t this out though  
nil.to\_s #=\> “”  
no need to re-scan a match if you can use $1, $2, etc

module ANSIParser  
ANSI\_MATCH = /\e[(\d+);(\d+)\*m/

def self.ansi\_to\_array(str)  
str = str.to\_s  
ret = []

```
str.scan(ANSI_MATCH) do |match|
  ret << $`.to_s << $1.to_i << $2.to_i
end

ret << $'.to_s

```

end  
end

sorry for using the Perl variables 🙂 if you want you can use  
Regexp.last\_match.post\_match

---

<div class="post-metadata">

**Author:** ![ihaveguts](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/i/f05b48/32.png) [@ihaveguts](https://www.ruby-forum.com/u/ihaveguts)\
**Post date:** [November 7, 2006, 11:06am UTC](https://www.ruby-forum.com/t/ugly-code-suggestions/74967/3 "2006-11-07T11:06:01Z")

</div>

On 05.11.2006 22:13, Gabriele M. wrote:

> ```
> return ret
> 
> ```
> 
> end  
> end
> 
> # TEST:
> 
> ansistr = “\e[31mred,\e[32;1m\e[32;1mbold green\e[33;32;31mred anyway,  
> still bold\e[33;32;31m”
> 
> puts ansistr # you should see colors if your terminal supports ANSI escapes  
> puts ANSIParser::ansi\_to\_array(ansistr).inspect

> > ansistr = “\e[31mred,\e[32;1m\e[32;1mbold green\e[33;32;31mred  
> > anyway, still bold\e[33;32;31m”  
> > =\> “\e[31mred,\e[32;1m\e[32;1mbold green\e[33;32;31mred anyway, still  
> > bold\e[33;32;31m”

> > ansistr.split(%r{(\e[\d+(?:;\d+)\*m)}).inject([]) do |arr, s|  
> > ?\> case s
> 
> > ```
> > when ""
> > arr
> > when %r{^\e}
> > arr.concat( s.scan( /\d+/ ).map {|x| x.to_i} )
> > else
> > 
> > ```

?\> arr \<\< s

> > end  
> > end  
> > =\> [31, “red,”, 32, 1, 32, 1, “bold green”, 33, 32, 31, “red anyway,  
> > still bold”, 33, 32, 31]

Kind regards

```
robert
```

---

<div class="post-metadata">

**Author:** ![ihaveguts](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/i/f05b48/32.png) [@ihaveguts](https://www.ruby-forum.com/u/ihaveguts)\
**Post date:** [November 7, 2006, 11:06am UTC](https://www.ruby-forum.com/t/ugly-code-suggestions/74967/4 "2006-11-07T11:06:10Z")

</div>

Il giorno 06/nov/06, alle ore 10:35, Robert K. ha scritto:

> > > ```
> > > arr.concat( s.scan( /\d+/ ).map {|x| x.to_i} )
> > > else
> > > 
> > > ```
> 
> ?\> arr \<\< s
> 
> > > end  
> > > end  
> > > =\> [31, “red,”, 32, 1, 32, 1, “bold green”, 33, 32, 31, “red  
> > > anyway, still bold”, 33, 32, 31]
> 
> Kind regards
> 
> robert

Cool!  
Thanks 😃

---

<div class="post-metadata">

**Author:** ![ihaveguts](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/i/f05b48/32.png) [@ihaveguts](https://www.ruby-forum.com/u/ihaveguts)\
**Post date:** [November 7, 2006, 11:05am UTC](https://www.ruby-forum.com/t/ugly-code-suggestions/74967/5 "2006-11-07T11:05:10Z")

</div>

HI –

On Mon, 6 Nov 2006, greg wrote:

> couple of ideas for you- didn’t this out though  
> nil.to\_s #=\> “”  
> no need to re-scan a match if you can use $1, $2, etc

The reason is that you might have more than one ;\d+ sequence, and the  
scan operation with captures will only give you the last one:

> > p “abc;31;32;33”.scan(/abc(;\d+)\*/)  
> > =\> [[";33"]]

I don’t know whether the named captures in oniguruma might help  
here…

David
