# Substitution with Hash

**URL:** <https://www.ruby-forum.com/t/substitution-with-hash/114325>\
**Category:** Ruby\
**Created:** [September 11, 2007, 12:41pm UTC](https://www.ruby-forum.com/t/substitution-with-hash/114325 "2007-09-11T12:41:37Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![jarvo88](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/a8b319/32.png) [@jarvo88](https://www.ruby-forum.com/u/jarvo88)\
**Post date:** [September 11, 2007, 12:41pm UTC](https://www.ruby-forum.com/t/substitution-with-hash/114325/1 "2007-09-11T12:41:37Z")

</div>

Ok i’ll try to explain what i mean as well as i can

Lets say i have a hash like this

hash { ‘a’ =\> ‘1’ } #just as example, its actually far bigger

and if a user inputs abcdabcd i was it to sub all of the a’s with 1’s…

As i said, the hash is far larger which is why i can’t just do it with  
gsub…

Any ideas?

Thanks in advance…

Lee

---

<div class="post-metadata">

**Author:** ![jarvo88](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/a8b319/32.png) [@jarvo88](https://www.ruby-forum.com/u/jarvo88)\
**Post date:** [September 11, 2007, 12:50pm UTC](https://www.ruby-forum.com/t/substitution-with-hash/114325/2 "2007-09-11T12:50:20Z")

</div>

Lee J. wrote the following on 11.09.2007 12:41 :

> Any ideas?
> 
> Thanks in advance…
> 
> Lee

yourstring.split(//).map{|c| hash[c] || c}.join

---

<div class="post-metadata">

**Author:** ![jarvo88](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/a8b319/32.png) [@jarvo88](https://www.ruby-forum.com/u/jarvo88)\
**Post date:** [September 11, 2007, 12:58pm UTC](https://www.ruby-forum.com/t/substitution-with-hash/114325/3 "2007-09-11T12:58:21Z")

</div>

Lionel B. wrote the following on 11.09.2007 12:48 :

> > As i said, the hash is far larger which is why i can’t just do it with  
> > yourstring.split(//).map{|c| hash[c] || c}.join

Note that if your hash is only used to convert single characters to  
single characters, you can use String#tr (or tr!). If you are after  
performance, as you must prepare the strings used by String#tr from your  
hash, you’ll have to bench it to see if it’s worth it in your use case  
even if String#tr is faster in itself.  
If you are processing UTF-8 content, String#tr is probably not safe  
(there are libraries out there for fixing this though IIRC), but my  
first answer probably is (assuming $KCODE=‘u’; require ‘jcode’…) as  
the regexp processing is utf-8 aware, so the String#split should be  
safe.

Lionel

---

<div class="post-metadata">

**Author:** ![jarvo88](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/a8b319/32.png) [@jarvo88](https://www.ruby-forum.com/u/jarvo88)\
**Post date:** [September 11, 2007, 3:37pm UTC](https://www.ruby-forum.com/t/substitution-with-hash/114325/4 "2007-09-11T15:37:42Z")

</div>

2007/9/11, Lee J. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> "hmm ~‘.split(/ /).map{|c| h[c] || c}.join(’ ')
> 
> Outputs hmm ~, but obviously doing things like question marks wont work,  
> Maybe i’ll have to use loops and string#tr

I’d rather not do the split step, IMHO direct replacement will be  
faster:

h = {“#126” =\> “~”}  
s.gsub(/&([^;]+);/) {|c| h[c] || “&#{c};”}

Btw, I believe there are standard classes that do this type of  
replacement (entities in HTML documents) - maybe it’s in CGI.

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![jarvo88](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/a8b319/32.png) [@jarvo88](https://www.ruby-forum.com/u/jarvo88)\
**Post date:** [September 11, 2007, 1:51pm UTC](https://www.ruby-forum.com/t/substitution-with-hash/114325/5 "2007-09-11T13:51:19Z")

</div>

Thanks that worked well, And no its not single chars, Which is the only  
reason i’m doing it this way…

I have to split on whitespace (/ /) because spliting on characters would  
obviously split the text i want to transform, which means it wont match  
if the characters are trailing another word, HTML special chars for  
example

h = {"~" =\> “~”}

"hmm ~’.split(/ /).map{|c| h[c] || c}.join(’ ')

Outputs hmm ~, but obviously doing things like question marks wont work,  
Maybe i’ll have to use loops and string#tr

---

<div class="post-metadata">

**Author:** ![jarvo88](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/a8b319/32.png) [@jarvo88](https://www.ruby-forum.com/u/jarvo88)\
**Post date:** [September 12, 2007, 1:53am UTC](https://www.ruby-forum.com/t/substitution-with-hash/114325/6 "2007-09-12T01:53:45Z")

</div>

Lee J. wrote:

> Thanks that worked well, And no its not single chars, Which is the only  
> reason i’m doing it this way…
> 
> I have to split on whitespace (/ /) because spliting on characters would  
> obviously split the text i want to transform, which means it wont match  
> if the characters are trailing another word, HTML special chars for  
> example
> 
> h = {"~" =\> “~”}

If you’re just trying to translate numeric html entities it’s easy:  
str.gsub(/&#(\d+);/){ [$1.to\_i].pack(‘U’) }  
If you also want named entities I suggest the htmlentities gems.  
If it’s for a more general case, how about:  
rx = Regexp.new(hash.keys.map{|k|Regexp.escape(k)}.join("|"))  
str.gsub(rx){ hash[$&] }

Daniel

---

<div class="post-metadata">

**Author:** ![jarvo88](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/a8b319/32.png) [@jarvo88](https://www.ruby-forum.com/u/jarvo88)\
**Post date:** [September 11, 2007, 4:19pm UTC](https://www.ruby-forum.com/t/substitution-with-hash/114325/7 "2007-09-11T16:19:52Z")

</div>

Robert K. wrote:

> 

If it’s all for html entities yes. I’m not sure of what the actual use  
case is though.

> h = {"#126" =\> “~”}  
> s.gsub(/&([^;]+);/) {|c| h[c] || “&#{c};”}
> 
> Btw, I believe there are standard classes that do this type of  
> replacement (entities in HTML documents) - maybe it’s in CGI.

The htmlentities gem (more robust than CGI with UTF-8…) is quite good.
