Working on a rails project where there's an order confirmation string with a credit card number with all but the last four digits starred out. What's the proper way to do a string substitution?
What's the operation to get this
credit_card_number = "1111111111111111"
to this?
credit_card_number = "************1111"
Thanks,
Kenji
Here's a regex approach:
x.gsub!(/.(?=....)/, '*')
Here's an approach using string indexing:
x = '*' * (x.size - 4) + x[-4, 4]
If you're using ActiveMerchant, ActiveMerchant::Billing::CreditCard has an instance method called display_number which does this e.g. XXXX-XXXX-XXXX-4338
If you're not, copy activemerchant:
def last_digits(number)
number.to_s.length <= 4 ? number : number.to_s.slice(-4..-1)
end
def mask(number)
"XXXX-XXXX-XXXX-#{last_digits(number)}"
end
credit_card_number = "1111111111111111"
display_number = mask credit_card_number
You could use Ruby's gsub method and a regular expression to hide some of the numbers in the account number string:
hidenumber = "123-123-1234"
hidenumber.gsub(/(\d{3}-\d{3})/,"xxx-xxx")
Related
I am using Dentaku gem to solve little complex expressions like basic salary is 70% of Gross salary. As the formulas are user editable so I worked on dentaku.
When I write calculator = Dentaku::Calculator.new to initialize and then enter the command calculator.evaluate("60000*70%") then error comes like below:
Dentaku::ParseError: Dentaku::AST::Modulo requires numeric operands
from /Users/sulman/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/dentaku-2.0.8/lib/dentaku/ast/arithmetic.rb:11:in `initialize'
I have array is which formula is stored like: ["EarningItem-5","*","6","7","%"] where EarningItem-5 is an object and has value 60000
How can I resolve such expressions?
For this particular case you can use basic_salary = gross_salary * 0.7
Next you need to create the number field in your views which accepts 0..100 range. At last, set up the after_save callback and use this code:
model
after_create :percent_to_float
protected
def percent_to_float
self.percent = percent / 100.0
self.save
end
edit:
Of course, you can simply use this formula without any callbacks:
basic_salary = gross_salary / 100.0 * 70
where 70 is user defined value.
Dentaku does not appear to support "percent". Try this instead
calculator.evaluate('60000 * 0.7')
How do I turn "1.5k" into 1500 or "1,766" into "1766" with ruby or rails?
Thanks!
You can do it using ruby without rails.
n = "1,200.5k"
n = n.to_s.gsub(/,+/, '')
n = (n[-1] == 'k' ? n[0...-1].to_f * 1000 : n).to_i
puts n
As for the case "1.5k" you can write a quick method that, if the .to_i() fails, looks for a k as the last character. You can get the last character by doing num_str[-1, 1], where num_str is the original string.
For the other case, I would recommend looking into the money gem. num = Money.parse("1,766").
I have such code in controller's method for rounding (only higher) and display ceil part of number:
#constr_num.each do |cn|
non_original_temp_var2 = get_non_tecdoc_analogs(cn.ARL_SEARCH_NUMBER, #article.supplier.SUP_BRAND, false)
non_original << non_original_temp_var2
end
#non_original = non_original.flatten!
#non_original.each do |n_original|
n_original.price = my_round2(n_original.price * markup_for_user)
end
def my_round2 a
res = (a / 1.0).ceil * 1
res
end
But for some reasons i see with every price comma with 0 after it, for example: 5142.0 but it must be 5142
Main strange part is that, if i try to write:
n_original.price = 123
in view i see 123.0
What happend?
Only when i write in view (when displaying price):
price.ceil
i see normal numbers, without comma
What i di wrong? How to ceil my numbers with rounding (but only high, for example 2.24 is 3 3.51 is 4 and 2.0 is 2)? Becouse now for some reasons i see comma and nul after my number, even if i try to "hardcode" number in controller.
How about using the next or succ function of the Integer class? Try something like the following:
def my_round2 a
(a.is_a? Integer) ? a : a.to_i.next
end
If a is an Integer then return a otherwise cast it to Integer using the to_i method and call next or succ method on it.
Reference: http://www.ruby-doc.org/core-2.0/Integer.html
I guess I missed the second part of your question. To avoid the decimal places I guess you would have to use the a.to_i like Philip Hallstrom has suggested.
My guess is that your price field is a Float. Floats will be printed with a decimal spot by default. You need to either cast it to an Integer earlier on (say in my_round2 method) or in your view task a .to_i onto the output.
I am generating a unique and random alphanumeric string segment to represent certain links that will be generated by the users. For doing that I was approaching with "uuid" number to ensure it's uniqueness and randomness, but, as per my requirements the string shouldn't be more than 5 characters long. So I dropped that idea.
Then I decided to generate such a string using random function of ruby and current time stamp.
The code for my random string goes like this:-
temp=DateTime.now
temp=temp + rand(DateTime.now.to_i)
temp= hash.abs.to_s(36)
What I did is that I stored the current DateTime in a temp variable and then I generated a random number passing the current datetime as parameter. Then in the second line actually added current datetime and random number together to make a unique and random string.
Soon I found,while I was testing my application in two different machines and send the request at the same time, it generated the same string(Though it's rare) once after more than 100 trials.
Now I'm thinking that I should add one more parameter like mac address or client ip address before passing to_s(36) on temp variable. But can't figure out how to do it and even then whether it will be unique or nor...
Thanks....
SecureRandom in ruby uses process id (if available) and current time. You can use the urlsafe_base64(n= 16) class method to generate the sequence you need. According to your requirements I think this is your best bet.
Edit: After a bit of testing, I still think that this approach will generate non-unique keys. The way I solved this problem for barcode generation was:
barcode= barcode_sql_id_hash("#{sql_id}#{keyword}")
Here, your keyword can be time + pid.
If you are certain that you will never need more than a given M amount of unique values, and you don't need more than rudimentary protection against guessing the next generated id, you can use a Linear Congruentual Generator to generate your identificators. All you have to do is remember the last id generated, and use that to generate a new one using the following formula:
newid = (A * oldid + B) mod M
If 2³² distinct id values are enough to suit your needs, try:
def generate_id
if #lcg
#lcg = (1664525 * #lcg + 1013904223) % (2**32)
else
#lcg = rand(2**32) # Random seed
end
end
Now just pick a suitable set of characters to represent the id in as little as 6 character. Uppercase and lowercase letters should do the trick, since (26+26)^6 > 2^32:
ENCODE_CHARS = [*?a..?z, *?A..?Z]
def encode(n)
6.times.map { |i|
n, mod = n.divmod(ENCODE_CHARS.size)
ENCODE_CHARS[mod]
}.join
end
Example:
> 10.times { n = generate_id ; puts "%10d = %s" % [n, encode(n)] }
2574974483 = dyhjOg
3636751446 = QxyuDj
368621501 = bBGvYa
1689949688 = yuTgxe
1457610999 = NqzsRd
3936504298 = MPpusk
133820481 = PQLpsa
2956135596 = yvXpOh
3269402651 = VFUhFi
724653758 = knLfVb
Due to the nature of the LCG, the generated id will not repeat until all 2³² values have been used exactly once each.
There is no way you can generate a unique UUID with only five chars, with chars and numbers you have a basic space of around 56 chars, so there is a max of 56^5 combinations , aprox 551 million (Around 2^29).
If with this scheme you were about to generate 10.000 UUIDs (A very low number of UUIDs) you would have a probability of 1/5.000 of generating a collision.
When using crypto, the standard definition of a big enough space to avert collisions is around 2^80.
To put this into perspective, your algorithm would be better off if it generated just a random integer (a 32 bit uint is 2^32, 8 times the size you are proposing) which is clearly a bad idea.
Easy question here, probably, but searching did not find a similar question.
The # operator finds the length of a string, among other things, great. But with Lua being dynamically typed, thus no conversion operators, how does one type a number as a string in order to determine its length?
For example suppose I want to print the factorials from 1 to 9 in a formatted table.
i,F = 1,1
while i<10 do
print(i.."! == "..string.rep("0",10-#F)..F)
i=i+1
F=F*i
end
error: attempt to get length of global 'F' (a number value)
why not use tostring(F) to convert F to a string?
Alternatively,
length = math.floor(math.log10(number)+1)
Careful though, this will only work where n > 0!
There are probably a dozen ways to do this. The easy way is to use tostring as Dan mentions. You could also concatenate an empty string, e.g. F_str=""..F to get F_str as a string representation. But since you are trying to output a formatted string, use the string.format method to do all the hard work for you:
i,F = 1,1
while i<10 do
print(string.format("%01d! == %010d", i, F))
i=i+1
F=F*i
end
Isn't while tostring(F).len < 10 do useful?