in Elixir: string formatting - format

I have a transform rule:
"0549$2"
How do I apply this rule to strings in an Elixir?
In ruby i use:
format("0549%2$s", *["88", "77"])
=> "054977"
In Elixir I write:
:io.format("0549%2$s", ["88", "77"])
** (ArgumentError) argument error
(stdlib) :io.format(#PID<0.54.0>, "0549%2$s", ["88", "77"])
Because :io.format from erlang does not understand this format

You might use :io_lib.format/2. It produces the charlist, that can be converted to binary afterwards:
"0549~i~s"
|> :io_lib.format(~w[77 88])
|> to_string()
#⇒ "054988"
~i stays for “ignore the next term”
~s for treating the parameter as a binary
Sidenote: io.format outputs the formatted string to the IO device, returning :ok.

So you want to replace all $ followed by an integer with the corresponding element (indexed from 1) of a list? Here's one way using Regex.replace/3:
defmodule A do
def format(string, list) do
Regex.replace(~r/\$(\d+)/, string, fn _, index ->
Enum.at(list, String.to_integer(index) - 1)
end)
end
end
IO.inspect A.format("0549$2", ["88", "77"])
IO.inspect A.format("0549$1", ["88", "77"])
Output:
"054977"
"054988"

Related

How to match and replace pattern without regex?

I was recently asked this in an interview and was figuring out a way to do this without using regex in Ruby as I was told it would be a bonus if you can solve it without using regex.
Question: Assume that the hash has 1 million key, value pairs and we have to be able to sub the variables in the string that are between % % this pattern. How would I be able to do this without regex.
We have a string str = "%greet%! Hi there, %var_1% that can be any other %var_2% injected to the %var_3%. Nice!, goodbye)"
we have a hash called dict = { greet: 'Hi there', var_1: 'FIRST VARIABLE', var_2: 'values', var_3: 'string', }
This was my solution:
def template(str, dict)
vars = value.scan(/%(.*?)%/).flatten
vars.each do |var|
value = value.gsub("%#{var}%", dict[var.to_sym])
end
value
end
There are many ways to solve this, but you will probably need some kind of parsing and / or lexical analysis if you don't want to use built-in pattern matching.
Let's keep it very simple and say that your string's content falls into two categories: text and variable which are separated by %, e.g. (you could also think of the variables being enclosed by %, but that's harder to implement)
str = "Hello %name%, hope to see you %when%!"
# TTTTTT VVVV TTTTTTTTTTTTTTTTTT VVVV T
As you can see, the categories are alternating. We can utilize this and write a little helper method that turns a string into a list of [type, value] pairs, something like this:
def each_part(str)
return enum_for(__method__, str) unless block_given?
type = [:text, :var].cycle
buf = ''
str.each_char do |char|
if char != '%'
buf << char
else
yield type.next, buf
buf = ''
end
end
yield type.next, buf
end
It starts by defining an enumerator that will cycle between the two types and an empty buffer. It will then read each_char from the string. If the char is not %, it will just append it to the buffer and keep reading. Once it encounters a %, it will yield the current buffer along with the type and start a new buffer (next will also switch the type). After the loop ends, it will yield once more to output the remaining characters.
It outputs this kind of data:
each_part(str).to_a
#=> [[:text, "Hello "],
# [:var, "name"],
# [:text, ", hope to see you "],
# [:var, "when"],
# [:text, "!"]]
We can use this to convert the string:
dict = { name: 'Tom', when: 'soon' }
output = ''
each_part(str) do |type, value|
case type
when :text
output << value
when :var
output << dict[value.to_sym]
end
end
p output
#=> "Hello Tom, hope to see you soon!"
You could of course combine parsing and evaluation, but I like the separation. An full-fledged parser might involve even more steps.
A very simple approach:
First, split the string on '%':
str = "%greet%! Hi there, %var_1% that can be any other %var_2% injected to the %var_3%. Nice!, goodbye)"
chunks = str.split('%')
Now we can assume given the way the problem has been specified, that every other "chunk" will be a key to replace. Iterating with the index will make that easier to figure out.
chunks.each_with_index { |c, i| chunks[i] = (i.even? ? c : dict[c.to_sym]) }.join
Result:
"Hi there! Hi there, FIRST VARIABLE that can be any other values injected to the string. Nice!, goodbye)"
Note: this does not handle malformed input well at all.

Formatted output in ruby using p function

How can we obtain formatted output using p function. of ruby.
I need to print a float with exactly two decimal places.
I want to do it using minimum characters so i want to use p function instead of puts and printf.
i have tried this
printf"%.2f",a.abs/2
Any idea on how to reduce characters ?
inspect is the method you need to override for p
class Float
def inspect
sprintf "%.2f", self
end
end
Result
p 12.0
#=> 12.00
Assuming you're ok about a string being returned, you can use use Kernel#sprintf
sprintf "%.2f", 1.234
=> "1.23"
Note that printf is really just sugar for IO.write(sprint()) so the above should be considered equiavelent.
You can use the method String#%
str % arg → new_str
Format—Uses str as a format specification, and returns the result of applying it to arg. If the format specification contains more than one substitution, then arg must be an Array or Hash containing the values to be substituted. See Kernel::sprintf for details of the format string.
In your example:
a = 5.3
p"%.2f"%a
If you use a formula you need additional braces:
p"%.2f"%(a.abs/2)

how can i return the value after forwardslash from string

I have a string "/com.bing.bang/20140620%2F351811403305411724"
I am trying to seperate "com.bing.bang" and "20140620%2F351811403305411724"
Simple .split['/'] won't work because string starts with "/"
How this can be done?
You can do
_, *arr = s.split '/'
arr
#=> ["com.bing.bang", "20140620%2F351811403305411724"]
x = "/com.bing.bang/20140620%2F351811403305411724"
bits = x.split("/")
bits.shift if bits[0] == "" # dump the initial ""
(part1,part2) = bits
Split will work if you simply remove the leading / before you use it:
str = "/com.bing.bang/20140620%2F351811403305411724"
fst, snd = str[1..-1].split('/')
fst # => "com.bing.bang"
snd # => "20140620%2F351811403305411724"
Also str.split['/'] doesn't do anything useful, it in fact raises an exception, because split is a method. To call it you must use parentheses (rounded brackets) like so: str.split('/').
The reason for the exception is that the former expression actually looks like this to the interpreter: (str.split)['/'] so it will split str on its spaces, and then it treats the ['/'] as an index into the array that is produced from the split.
This is a problem because the index you gave it is a string, and arrays only accept Integer indices, so you end up getting a TypeError raised.

How to obtain the binary literal from a integer in Ruby?

I would like to get the binary literal corresponding from a given integer, in this way:
4.to_literal
=> 0b100
Is there such to_literal method?
Use to_s with its optional base parameter to get a string.
4.to_s(2) #=> "100"
You can't get a literal as output.
Use String#% or Kernel#sprintf (%#b as format specifier):
'%#b' % 4
# => "0b100"
sprintf('%#b', 4)
# => "0b100"

How to validate that a string is a proper hexadecimal value in Ruby?

I am writing a 6502 assembler in Ruby. I am looking for a way to validate hexadecimal operands in string form. I understand that the String object provides a "hex" method to return a number, but here's a problem I run into:
"0A".hex #=> 10 - a valid hexadecimal value
"0Z".hex #=> 0 - invalid, produces a zero
"asfd".hex #=> 10 - Why 10? I guess it reads 'a' first and stops at 's'?
You will get some odd results by typing in a bunch of gibberish. What I need is a way to first verify that the value is a legit hex string.
I was playing around with regular expressions, and realized I can do this:
true if "0A" =~ /[A-Fa-f0-9]/
#=> true
true if "0Z" =~ /[A-Fa-f0-9]/
#=> true <-- PROBLEM
I'm not sure how to address this issue. I need to be able to verify that letters are only A-F and that if it is just numbers that is ok too.
I'm hoping to avoid spaghetti code, riddled with "if" statements. I am hoping that someone could provide a "one-liner" or some form of elegent code.
Thanks!
!str[/\H/] will look for invalid hex values.
String#hex does not interpret the whole string as hex, it extracts from the beginning of the string up to as far as it can be interpreted as hex. With "0Z", the "0" is valid hex, so it interpreted that part. With "asfd", the "a" is valid hex, so it interpreted that part.
One method:
str.to_i(16).to_s(16) == str.downcase
Another:
str =~ /\A[a-f0-9]+\Z/i # or simply /\A\h+\Z/ (see hirolau's answer)
About your regex, you have to use anchors (\A for begin of string and \Z for end of string) to say that you want the full string to match. Also, the + repeats the match for one or more characters.
Note that you could use ^ (begin of line) and $ (end of line), but this would allow strings like "something\n0A" to pass.
This is an old question, but I just had the issue myself. I opted for this in my code:
str =~ /^\h+$/
It has the added benefit of returning nil if str is nil.
Since Ruby has literal hex built-in, you can eval the string and rescue the SyntaxError
eval "0xA" => 10
eval "0xZ" => SyntaxError
You can use this on a method like
def is_hex?(str)
begin
eval("0x#{str}")
true
rescue SyntaxError
false
end
end
is_hex?('0A') => true
is_hex?('0Z') => false
Of course since you are using eval, make sure you are sending only safe values to the methods

Resources