using eval to convert string into hash - ruby-on-rails

I have string like this
a="{\"company\"=>\"khkhkh\", \"email\"=>\"hjkh#hkkj.kjh\",\"address\"=>\"yiyiyu\", \"date\"=>Mon, 28 Apr 2014 13:14:10 BST +01:00}"
but i have made a mistake when generating this string. that is, i appended the date without converting to string. So now if i try to get back this into a hash using eval(a) . This throws a error, with is acceptable.
SyntaxError: (eval):1: syntax error, unexpected tCONSTANT, expecting => ....
Is there any way to get that hash back, since iam in a situation that i cant regenerate this string.
Any help would be highly appreciable.
Thanks.

For your immediate predicament:
a.gsub(/\"date\"\s*=>(.*?)(\}|,\s*\")/, '"date"=>"\1"\2')
This should work even if the date is not the last entry of the hash.
For the next time around: It is really not a good idea to serialize data by manually turning them into code that you eval later.
In most cases your best bet is probably to just generate JSON and parse that later. Using a proper JSON serializer/generator will also make sure your data is syntactically correct.

If the date is always last you could go with the straightforward approach:
date = a.gsub(/[\{\}]/, '').split('=>').last
a.gsub(date, "\"#{date}\"")
Will return
"{\"company\"=>\"khkhkh\", \"email\"=>\"hjkh#hkkj.kjh\",\"address\"=>\"yiyiyu\", \"date\"=>\"Mon, 28 Apr 2014 13:14:10 BST +01:00\"}"

If you have multiple dates, try to replace them with quoted dates by regexp:
wrong_data = "" # your string
correct_data = wrong_data.gsub(/(\w{3}, \d{2} \w{3} \d{4} \d{2}:\d{2}:\d{2} \w{3} \+\d{2}:\d{2})/, '"\1"')
eval(correct_data)
PS. As #Gene truly noticed, you should avoid using eval in your code.

Related

Ruby 'strptime()' not raising ArgumentError when passing invalid date format'

I could use some help with an issue I am facing in a Rails project. I am using the strptime function to return a Date object from an inputted string time and target format:
date = Date.strptime(date, '%Y-%m')
And it seems when I pass in a Date that doesn't match that pattern, i.e. 01-01-24, it does not throw an ArgumentError for me to catch and do anything with. It does catch an invalid input like this: 01-2024 though. Is there a certain kind of validation I can do here to catch this kind of error and check that the RegEx pattern matches?
Date#strptime format is using '%Y-%m' as [year]-[month] so in the case of '01-01-2024' it is seen as [01]-[01]-2024 and parsed to that date structure.
strptime does not respect %Y as having a minimum width so your current expression is essentially equivalent to /\A-?\d+-(?:1[0-2]|0?[1-9])/ (any number of digits followed by a hyphen followed by 1-12 optionally 0 padded)
'01-2024' only raises an error because 20 is not a valid month. For Example: '01-1299' would not raise an error.
Rather than relying on this naivety, you could validate your "date pattern" using a Regexp e.g.
date.match?(/\A\d{4}-(?:1[0-2]|0[1-9])\z/)
Using pry to investigate with:
[22] pry(main)> date = Date.strptime('calimero', '%Y-%m')
Date::Error: invalid date
from (pry):20:in `strptime'
it throws a Date::Error exception

Rails strip all except numbers commas and decimal points

Hi I've been struggling with this for the last hour and am no closer. How exactly do I strip everything except numbers, commas and decimal points from a rails string? The closest I have so far is:-
rate = rate.gsub!(/[^0-9]/i, '')
This strips everything but the numbers. When I try add commas to the expression, everything is getting stripped. I got the aboves from somewhere else and as far as I can gather:
^ = not
Everything to the left of the comma gets replaced by what's in the '' on the right
No idea what the /i does
I'm very new to gsub. Does anyone know of a good tutorial on building expressions?
Thanks
Try:
rate = rate.gsub(/[^0-9,\.]/, '')
Basically, you know the ^ means not when inside the character class brackets [] which you are using, and then you can just add the comma to the list. The decimal needs to be escaped with a backslash because in regular expressions they are a special character that means "match anything".
Also, be aware of whether you are using gsub or gsub!
gsub! has the bang, so it edits the instance of the string you're passing in, rather than returning another one.
So if using gsub! it would be:
rate.gsub!(/[^0-9,\.]/, '')
And rate would be altered.
If you do not want to alter the original variable, then you can use the version without the bang (and assign it to a different var):
cleaned_rate = rate.gsub!(/[^0-9,\.]/, '')
I'd just google for tutorials. I haven't used one. Regexes are a LOT of time and trial and error (and table-flipping).
This is a cool tool to use with a mini cheat-sheet on it for ruby that allows you to quickly edit and test your expression:
http://rubular.com/
You can just add the comma and period in the square-bracketed expression:
rate.gsub(/[^0-9,.]/, '')
You don't need the i for case-insensitivity for numbers and symbols.
There's lots of info on regular expressions, regex, etc. Maybe search for those instead of gsub.
You can use this:
rate = rate.gsub!(/[^0-9\.\,]/g,'')
Also check this out to learn more about regular expressions:
http://www.regexr.com/

write Regex to find match

I never wrote any complex regular expression before, and what I need seems to be (at least) a bit complicated.
I need a Regex to find matches for the following:
"On Fri, Jan 16, 2015 at 4:39 PM"
Where On will always be there;
then 3 characters for week day;
, is always there;
space is always there;
then 3 characters for month name;
space is always there;
day of month (one or two numbers);
, is always there;
space is always there;
4 numbers for year;
space at space always there;
time (have to match 4:39 as well as 10:39);
space and 2 caps letters for AM or PM.
Here's a very simple and readable one:
/On \w{3}, \w{3} \d{1,2}, \d{4} at \d{1,2}:\d{2} [AP]M/
See it on rubular
Try this:
On\s+(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun), (?:Jan|Feb|Mar|Apr|May|June|July|Aug|Sept|Oct|Nov|Dec) \d{1,2}, \d{4} at \d{1,2}:\d{2} (?:AM|PM)
/On \w{3}, \w{3} \d{1,2}, \d{4} at \d{1,2}:\d{1,2} [A-Z]{2}/
# \w{3} for 3 charecters
# \d{1,2} for a or 2 digits
# \d{4} for 4 digits
# [A-Z]{2} for 2 capital leters
You could try the below regex and it won't check for the month name or day name or date.
^On\s[A-Z][a-z]{2},\s[A-Z][a-z]{2}\s\d{1,2},\s\d{4}\sat\s(?:10|4):39\s[AP]M$
DEMO
You can use Rubular to construct and test Ruby Regular Expressions.
I have put together an Example: http://rubular.com/r/45RIiwheqs
Since it looks you try to parse dates, you should use Date.strptime.
/On [A-Za-z]{3}, [A-Za-z]{3} \d{1,2}, \d{4} at \d{1,2}:\d{1,2}/g
The way you are describing the problem makes me thing that the format will always be preserved.
I would then in your case use the Time.parse function, passing the format string
format = "On %a, %b"On Fri, Jan 16, 2015 at 4:39 PM", format)
which is more readable than a regexp (in my opinion) and has the added value that it returns a Time object, which is easier to use than a regexp match, in case you need to perform other time-based calculations.
Another good thing is that if the string contains an invalid date (like "On Mon, Jan 59, 2015 at 37:99 GX" ) the parse function will raise an exception, so that validation is done for free for you.

Parsing date and time with the new java.time.DateTimeFormatter

I have a date of this type: 2004-12-31 23:00:00-08 but no one of the patterns i know and i have used from the documentation is working. I thought it should something like "yyyy-MM-dd HH:mm:ssX" but it isn't working.
Sorry for you, but this is a known bug and was already reported in January 2014. According to the bug log a possible solution is deferred.
A simple workaround avoiding alternative external libraries is text preprocessing. That means: Before you parse the text you just append the prefix ":00". Example:
String input = "2004-12-31 23:00:00-08";
String zero = ":00";
if (input.charAt(input.length() - 3) == ':') {
zero = "";
}
ZonedDateTime zdt =
ZonedDateTime.parse(
input + zero,
DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ssXXX"));
System.out.println(zdt);
// output: 2004-12-31T23:00-08:00
UPDATE due to debate with #Seelenvirtuose:
As long as you ONLY have offsets with just hours but without minute part then the pattern "uuuu-MM-dd HH:mm:ssX" will solve your problem, too (as #Seelenvirtuose has correctly stated in his comment).
But if you have to process a list of various strings with mixed offsets like "-08", "Z" or "+05:30" (latter is India standard time) then you should usually apply the pattern containing three XXX. But this currently fails (have verified it by testing in last version of Java-8). So in this case you still have to do text preprocessing and/or text analysis.

How do i parse out the last portion of a ruby string?

I have this string
location = '\\dev-something-again-n2\Staples\Started\477'
location = '\\dev-something-again-n2\Staples\Started\477\'
and i need to pull out the 477 out of it...any ideas of a good way to do this ...i was trying
location.partition("\")
but got nothing ....
location.split('\\').last
partition isn't the right tool here - it splits once on the string, rather than splitting on all the places it is found, as documented:
partition(sep) => [head, sep, tail] click to toggle source
Searches the string for sep and returns the part before it, the sep, and the part after it. If sep is not found, returns str and two empty strings. If no argument is given, Enumerable#partition is called.
split is the right tool for the job, if you want to do this by breaking the content apart.
Try using:
File.split(location).last
or
File.basename(location)
location.chomp('\\').match(/(?:.*\\)(.*)/)[1]

Resources