Ruby transliteration using hash [closed] - ruby

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I try to make Cyrillic => Latin transliteration using hash, I use # encoding: utf-8 and ruby 1.9.3. I want this code to change the value of file_name. Why does this code leave file_name unchanged?
abc = Hash.new
abc = {"a" => "a", "b" => "б", "v" => "в", 'g' => "г", 'd'=> "д", 'jo' => "ё", 'zh' => "ж", 'th' => "з", 'i' => "и", 'l' => "л", 'm' => "м", 'n' => "н",'p' => "п", 'r' => "р", 's' => "с", 't' => "т", 'u' => "у", 'f' => "ф", 'h' => "х", 'c' => "ц", 'ch' => "ч", 'sh' => "ш", 'sch' => "щ", 'y' => "ы",'u' => "ю", 'ja' => "я"}
file_name.each_char do |c|
abc.each {|key, value| if c == value then c = key end }
end

The problem with .each_char is that the block variable - c in your question - does not point back to the character in the string allowing to alter the string in situ. There are ways you could make that per-character mapping work from there (using a .map followed by a .join for instance) - but they are inefficient compared to .tr! or .gsub! for your purpose, because breaking the string out into an array of characters and reconstructing it involves creating many Ruby objects.
I think you need to do something like
file_name.tr!( 'aбвгдилмнпрстуфхцыю', 'abvgdilmnprstufhcyu' )
which covers the single letter conversions very efficiently. You then have some multi-letter conversions. I would use gsub! for that, and an inverted copy of your hash
latin_of = {"ё"=>"jo", "ж"=>"zh", "з"=>"th", "ч"=>"ch",
"ш"=>"sh", "щ"=>"sch", "я"=>"ja"}
file_name.gsub!( /[ёжзчшщя]/ ) { |cyrillic| latin_of[ cyrillic ] }
Note, unlike each_char, the return value of the block in .gsub! is used to replace whatever you matched in the original string. The above code uses an inversion of your original hash to quickly find the correct Latin replacement for the matched Cyrillic character.
You don't need tr! . . . instead, if you prefer, just use an inversion of your original hash in one pass using this second syntax. The cost of using two methods probably means you don't really gain that much from using .tr!. But you should know about String#tr! method, it can be very handy.
Edit: As suggested in comments, .gsub! can do a lot more for you here. Assuming latin_of was the complete hash with Cyrillic keys and the Latin values, you could do this:
file_name.gsub!( Regexp.union(latin_of.keys), latin_of )
Two things to note:
Regexp.union(latin_of.keys) is taking an array of the keys you want to convert and ensuring gsub will find them ready for replacement in the String
gsub! accepts a hash as the second parameter, and converts each match by looking it up as a key and replacing it with the associated value - exactly the behaviour you are looking for.

Related

Ruby - replace a letter for another Explanation for my code [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 months ago.
Improve this question
I got to solve the problem I was trying to solve, but the thing is that I am not sure why it worked, I just started adding methods.
So if anyone could explain why worked:
def replace(string1, letter_a, letter_b)
replacements = {letter_a => letter_b}
#this is the part I am not sure why is working:
initial_string.split('').map{|i| replacements[i] || i}.join
end
Firstly I recommend to use built-in methods String#gsub or String#tr
string.gsub(%r{#{replaceable_letter}}, replacing_letter)
"abcdef".gsub(/a/, "b") # => "bbcdef"
string.tr(replaceable_letter, replacing_letter)
"abcdef".tr("a", "b") # => "bbcdef"
Instead of initial_string.split('').map you can use initial_string.each_char.map
Explanation of your code:
replacements = {letter_a => letter_b}
is hash where replaceable letter is key and replacing letter is value
For example { "a" => "b" }
Than you split your string to chars array
After that map over this array
For every char you check the hash, for example:
replacements["a"] # => "b"
replacements["c"] # => nil
If hash has such key, you take replacing letter, if not take origin letter. Compare and read about || operator:
nil || "f" # => "f"
"b" || "a" # => "b"
And finally join new array

How do I split a string in ruby? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
In my test step, I need to split letters.
find(:xpath,"//*[]").text
gives a string like "No#xyz1", where No# is a static part.
I need xyz1. How do I get that part?
String#[] with positive lookbehind comes to the rescue:
"No#xyz1"[/(?<=No#).*/]
#⇒ "xyz1"
So in your matcher you can use:
find(:xpath,"//*[]").text[/(?<=No#).*/] == "xyz1"
There are many ways to achieve that. You can, for example, use regular expression and scan method:
[1] pry(main)> "No#xyz1".scan(/No#(.+)/).first.first
=> "xyz1"
or a "dummy" split on string too:
[4] pry(main)> "No#xyz1".split("No#")
=> ["", "xyz1"]
[5] pry(main)> "No#xyz1".split("No#").last
=> "xyz1"
I would recommend the first one, though.
String#partition works fine here.
Searches sep or pattern (regexp) in the string and returns the part
before it, the match, and the part after it. If it is not found,
returns two empty strings and str.
"No#xyz1".partition("No#")
# => ["", "No#", "xyz1"]
"No#xyz1".partition("NotHere")
# => ["No#xyz1", "", ""]
So you can use :
"No#xyz1".partition("No#").last
# => "xyz1"

Check the string with hash key

I am using Ruby 1.9.
I have a hash:
Hash_List={"ruby"=>"fun to learn","the rails"=>"It is a framework"}
I have a string like this:
test_string="I am learning the ruby by myself and also the rails."
I need to check if test_string contains words that match the keys of Hash_List. And if it does, replace the words with the matching hash value.
I used this code to check, but it is returning them empty:
another_hash=Hash_List.select{|key,value| key.include? test_string}
OK, hold onto your hat:
HASH_LIST = {
"ruby" => "fun to learn",
"the rails" => "It is a framework"
}
test_string = "I am learning the ruby by myself and also the rails."
keys_regex = /\b (?:#{Regexp.union(HASH_LIST.keys).source}) \b/x # => /\b (?:ruby|the\ rails) \b/x
test_string.gsub(keys_regex, HASH_LIST) # => "I am learning the fun to learn by myself and also It is a framework."
Ruby's got some great tricks up its sleeve, one of which is how we can throw a regular expression and a hash at gsub, and it'll search for every match of the regular expression, look up the matching "hits" as keys in the hash, and substitute the values back into the string:
gsub(pattern, hash) → new_str
...If the second argument is a Hash, and the matched text is one of its keys, the corresponding value is the replacement string....
Regexp.union(HASH_LIST.keys) # => /ruby|the\ rails/
Regexp.union(HASH_LIST.keys).source # => "ruby|the\\ rails"
Note that the first returns a regular expression and the second returns a string. This is important when we embed them into another regular expression:
/#{Regexp.union(HASH_LIST.keys)}/ # => /(?-mix:ruby|the\ rails)/
/#{Regexp.union(HASH_LIST.keys).source}/ # => /ruby|the\ rails/
The first can quietly destroy what you think is a simple search, because of the ?-mix: flags, which ends up embedding different flags inside the pattern.
The Regexp documentation covers all this well.
This capability is the core to making an extremely high-speed templating routine in Ruby.
You could do that as follows:
Hash_List.each_with_object(test_string.dup) { |(k,v),s| s.sub!(/#{k}/, v) }
#=> "I am learning the fun to learn by myself and also It is a framework."
First, follow naming conventions. Variables are snake_case, and names of classes are CamelCase.
hash = {"ruby" => "fun to learn", "rails" => "It is a framework"}
words = test_string.split(' ') # => ["I", "am", "learning", ...]
another_hash = hash.select{|key,value| words.include?(key)}
Answering your question: split your test string in words with #split and then check whether words include a key.
For checking if the string is substring of another string use String#[String] method:
another_hash = hash.select{|key, value| test_string[key]}

Regex without order [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
Suppose I have a list of characters [a,b,c] and I want to write a regular expression such that
any string is accepted if it has all the elements in the character list at-least once and the characters can appear in any order in the string.
Example of accepted strings
abc, aabbbc, bbaac, cab
Example of strings not accepteed
aaabb, bab, caa, aacd, deeff
Sets are much more suited for this purpose than regular expressions. What you're really trying to do is find out if (a, b, c) is a valid subset of your various strings. Here's an example of how to do that in Ruby:
> require "set"
=> true
> reference = Set.new("abc".split(""))
=> #<Set: {"a", "b", "c"}>
> test1 = Set.new("aabbbc".split(""))
=> #<Set: {"a", "b", "c"}>
> test2 = Set.new("caa".split(""))
=> #<Set: {"c", "a"}>
> reference.subset? test1
=> true
> reference.subset? test2
=> false
Consider this before reading on: regexes are not always the best way to solve a problem. If you are considering a regex but it's not obvious or easy to proceed, you may want to stop and consider if there is an easy non-regex solution handy.
I don't know what your specific situation is or why you think you need regex, so I'll assume you already know the above and answer your question as-is.
Based on the documentation, I beleive that Ruby supports positive lookaheads (also known as zero-width assertions). Being primarily a .NET programmer, I don't know Ruby well enough to say whether or not it supports non-fixed-length lookaheads (it's not found in all regex flavors), but if it does then you can easily apply three different lookaheads at the beginning of your expression to find each of the patterns or characters you need:
^(?=.*a)(?=.*b)(?=.*c).*
This will fail if any one of the lookaheads does not pass. This approach is potentially extremely powerful because you can have complex sub expressions in your lookahead. For example:
^(?=.*a[bc]{2})(?=.*-\d)(?=.*#.{3}%).*
will test that the input contains an a follwed by two characters which are each either a b or a c, a - followed by any digit and a # followed by any three characters followed by a %, in any particular order. So the following strings would pass:
#acb%-9
#-22%abb
This kind of complex pattern matching is difficult to succinctly duplicate.
To address this comment:
No there cannot be... so abcd is not accepted
You can use a negative lookahead to ensure that characters other than the desired characters are not present in the input:
^(?=.*a)(?=.*b)(?=.*c)(?!.*[^abc]).*
(As noted by Gene, the .* at the end is not necessary... I probably should have mentioned that. It's just there in case you actually want to select the text)
def acceptable? s
s =~ /(?=.*a)(?=.*b)(?=.*c)/
end
acceptable? 'abc' # => 0
acceptable? 'aabbbc' # => 0
acceptable? 'bbaac' # => 0
acceptable? 'cab' # => 0
acceptable? 'aaabb' # => nil
acceptable? 'bab' # => nil
acceptable? 'caa' # => nil
acceptable? 'aacd' # => nil
acceptable? 'deeff' # => nil
acceptable? 'abcd' # => 0
A regex that matches only the defined characters could be this:
(?=[bc]*a)(?=[ac]*b)(?=[ab]*c)[abc]*

what does ":foo" mean in ruby [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the colon operator in Ruby?
While learning Ruby I've come across the ":" operator on occasion. Usually I see it in the form of
:symbol => value
what does it mean?
It just indicates a that it is a symbol instead of a string. In ruby, it is common to use symbols instead of strings.
{:foo => value}
{'foo' => value}
It's basically a short-hand way of expressing a string. It can not contain spaces as you can imagine so symbols usually use underscores.
Try this on your own:
foo = :bar
foo.to_s # means to string
baz = 'goo'
baz.to_sym # means to symbol

Resources