Getting string characters in an array - ruby-on-rails

I have a string in ruby whose initial characters would be numbers and the last character would always be a letter. Some of the examples are: 2C, 1P, 45H, 135D.
I want to get an array which would have 2 objects, first would be the number and second would be the character.
Eg: for 2C, array would be [2, C]
for 45H, array would be [45, H]
for 135D, array would be [135, D]
I tried my_string[/(\d+)([A-Z])$/].split(//, 1), but it gives me an entire string in an array. Like ["2C"], ["45H"]
Am I missing something here?

I had to do some quick Googling to see how to use Ruby's split, but here is how you want to do it:
print '2C'.split(/(?<=\d)(?=[A-Z])/);
// ["2", "C"]
The expression works by doing a lookbehind ((?<=...)) and a lookahead ((?=...)). This means we will match the spot that has a digit to the left and a letter to the right.

You can use scan:
'150D'.scan(/\d+|\w/)
# => ["150", "D"]

Related

How to find a word in a single long string?

I want to be able to copy and paste a large string of words from say a text document where there are spaces, returns and not commas between each and every word. Then i want to be able to take out each word individually and put them in a table for example...
input:
please i need help
output:
{1, "please"},
{2, "i"},
{3, "need"},
{4, "help"}
(i will have the table already made with the second column set to like " ")
havent tried anything yet as nothing has come to mind and all i could think of was using gsub to turn spaces into commas and find a solution from there but again i dont think that would work out so well.
Your delimiters are spaces ( ), commas (,) and newlines (\n, sometimes \r\n or \r, the latter very rarely). You now want to find words delimited by these delimiters. A word is a sequence of one or more non-delimiter characters. This trivially translates to a Lua pattern which can be fed into gmatch. Paired with a loop & inserting the matches in a table you get the following:
local words = {}
for word in input:gmatch"[^ ,\r\n]+" do
table.insert(words, word)
end
if you know that your words are gonna be in your locale-specific character set (usually ASCII or extended ASCII), you can use Lua's %w character class for matching sequences of alphanumeric characters:
local words = {}
for word in input:gmatch"%w+" do
table.insert(words, word)
end
Note: The resulting table will be in "list" form:
{
[1] = "first",
[2] = "second",
[3] = "third",
}
(for which {"first", "second", "third"} would be shorthand)
I don't see any good reasons for the table format you have described, but it can be trivially created by inserting tables instead of strings into the list.

convert params array of numbers (a string) into an actual integer Array

I am sending an array ("[1,3,44,2,0]") via an Ajax PATCH call, and it arrives as:
Parameters: {"ids"=>"[1,3,44,2,0]"}
To taint check, I am using the following line - in which the match anchors against the start and end of the string, and makes sure that there is at least one digit, or that the numbers are comma separated:
raise "unexpected ids #{params[:ids]}" unless params[:ids].match(/\A\[(\d+,)*\d+\]\z/)
And to make an actual integer array out of it, I am using the following approach (strip the brackets, split on comma, convert each string element to an integer):
irb> "[1,3,44,2,0]"[1...-1].split(',').map {|e| e.to_i}
=> [1, 3, 44, 2, 0]
Is there a better (simpler, cheaper, faster) way of doing this?
Try
JSON.parse(params[:ids])
But I think you should check your Ajax call. It must be possible to pass the array not as a string.

Can someone explain why the .split method in Ruby works this way? [duplicate]

This question already has answers here:
Zero-length string being returned from String#split
(2 answers)
Closed 6 years ago.
Why does .split create an empty character when its argument is the first letter of the string, and it doesn't do the same when the argument is the last letter of the string? In the second example, doesn't it "say", since nothing is on my right I'll output "" ? (Is there a 'nil' at the end of the string?)
I know this is not a very relevant question, however, I'd like to understand why the method behaves this way. Thank you!
string = "aware"
string.split("a") --> # outputs: ["", "w", "re"]
string.split("e") --> # outputs: ["awar"]
Below is a simple example of behavioral oddity that String#split may seem to have:
"1234".split(/1/) # => ["", "234"]
It seems like the expected result of the above example would be [“234”] since it is splitting on the 1, but instead we’re getting an unexpected empty string.
**
How String#split works
**
Internally String#split only uses regular expression delimiters. If you pass in a string delimiter it will be escaped for a regular expression and then turned into a regular expression:
1 2 3 4
"1234".split("1") # is really the same as "1234".split( Regexp.new( Regexp.escape("1") ) )
For the remainder of this article when I refer to delimiter I am referring to a regular expression delimiter since internally that is what String#split uses.
String#split keeps track the track of five important pieces of information:
the string itself
a results array which is returned
the position marking where to start matching the string against the
delimiter. This is the start position and is initialized to 0.
the position marking where the string matched the delimiter. This is
the matched position and is initialized to 0.
the position marking the offset immediately following where the
string matched the delimiter
String#split operates in a loop. It continues to match the string against the delimiter until there are no more matches that can be found. It performs the following steps on each iteration:
from the start position match the delimiter against the string
set the matchedposition to where the delimiter matched the string
if the delimiter didn’t match the string then break the loop
create a substring using the start and matched positions of the
string being matched. Push this substring onto the results array
set the start position for the next iteration
With this knowledge let’s discuss how String#split handles the previous example of:
"1234".split(/1/) # => ["", "234"]
the first loop
the start position is initialized to 0
the delimiter is matched against the string “1234”
the first match occurs with the first character, “1” which is at
position 0. This sets the matched position to 0.
a substring is created using the start and matched positions and
pushed onto our result array. This gives us string[start,end] which
translates to “1234”[0,0] which returns an empty string.
the start position is reset to position 1
The second loop
start is now 1
The delimiter is matched against the remainder of our string, “234”
No match is found so the loop is finished.
A substring is created using the start position and remainder of the
string and pushed onto the results array
the results array is returned
Given how String#split works it is easy to see why we have that unexpected empty string in our results array. You should note that this only occurred because the regular expression matched our string at the first character. Below is an example where the delimiter doesn’t match the first character and there is no empty string:
"1234".split(/2/) # => ["1", "34"]
The pickaxe book says of string#split
If the limit parameter is omitted, trailing empty fields are suppressed. ... If negative, there is no limit to the number of fields returned and trailing null [empty] fields are not suppressed. So:
irb(main):001:0> "aware".split('e')
=> ["awar"]
irb(main):002:0> "aware".split('e',-1)
=> ["awar", ""]

Why do you use %w[] in rails?

Why would you ever use %w[] considering arrays in Rails are type-agnostic?
This is the most efficient way to define array of strings, because you don't have to use quotes and commas.
%w(abc def xyz)
Instead of
['abc', 'def', 'xyz']
Duplicate question of
http://stackoverflow.com/questions/1274675/what-does-warray-mean
http://stackoverflow.com/questions/5475830/what-is-the-w-thing-in-ruby
For more details you can follow https://simpleror.wordpress.com/2009/03/15/q-q-w-w-x-r-s/
These are the types of percent strings in ruby:
%w : Array of Strings
%i : Array of Symbols
%q : String
%r : Regular Expression
%s : Symbol
%x : Backtick (capture subshell result)
Let take some example
you have some set of characters which perform a paragraph like
Thanks for contributing an answer to Stack Overflow!
so when you try with
%w(Thanks for contributing an answer to Stack Overflow!)
Then you will get the output like
=> ["Thanks", "for", "contributing", "an", "answer", "to", "Stack", "Overflow!"]
if you will use some sets or words as a separate element in array so you should use \
lets take an example
%w(Thanks for contributing an answer to Stack\ Overflow!)
output would be
=> ["Thanks", "for", "contributing", "an", "answer", "to", "Stack Overflow!"]
Here ruby interpreter split the paragraph from spaces within the input. If you give \ after end of word so it merge next word with the that word and push as an string type element in array.
If can use like below
%w[2 4 5 6]
if you will use
%w("abc" "def")
then output would be
=> ["\"abc\"", "\"def\""]
%w(abc def xyz) is a shortcut for ["abc", "def","xyz"]. Meaning it's a notation to write an array of strings separated by spaces instead of commas and without quotes around them.

Best way to count words in a string in Ruby?

Is there anything better than string.scan(/(\w|-)+/).size (the - is so, e.g., "one-way street" counts as 2 words instead of 3)?
string.split.size
Edited to explain multiple spaces
From the Ruby String Documentation page
split(pattern=$;, [limit]) → anArray
Divides str into substrings based on a delimiter, returning an array
of these substrings.
If pattern is a String, then its contents are used as the delimiter
when splitting str. If pattern is a single space, str is split on
whitespace, with leading whitespace and runs of contiguous whitespace
characters ignored.
If pattern is a Regexp, str is divided where the pattern matches.
Whenever the pattern matches a zero-length string, str is split into
individual characters. If pattern contains groups, the respective
matches will be returned in the array as well.
If pattern is omitted, the value of $; is used. If $; is nil (which is
the default), str is split on whitespace as if ' ' were specified.
If the limit parameter is omitted, trailing null fields are
suppressed. If limit is a positive number, at most that number of
fields will be returned (if limit is 1, the entire string is returned
as the only entry in an array). If negative, there is no limit to the
number of fields returned, and trailing null fields are not
suppressed.
" now's the time".split #=> ["now's", "the", "time"]
While that is the current version of ruby as of this edit, I learned on 1.7 (IIRC), where that also worked. I just tested it on 1.8.3.
I know this is an old question, but this might be useful to someone else looking for something more sophisticated than string.split. I wrote the words_counted gem to solve this particular problem, since defining words is pretty tricky.
The gem lets you define your own custom criteria, or use the out of the box regexp, which is pretty handy for most use cases. You can pre-filter words with a variety of options, including a string, lambda, array, or another regexp.
counter = WordsCounted::Counter.new("Hello, Renée! 123")
counter.word_count #=> 2
counter.words #=> ["Hello", "Renée"]
# filter the word "hello"
counter = WordsCounted::Counter.new("Hello, Renée!", reject: "Hello")
counter.word_count #=> 1
counter.words #=> ["Renée"]
# Count numbers only
counter = WordsCounted::Counter.new("Hello, Renée! 123", rexexp: /[0-9]/)
counter.word_count #=> 1
counter.words #=> ["123"]
The gem provides a bunch more useful methods.
If the 'word' in this case can be described as an alphanumeric sequence which can include '-' then the following solution may be appropriate (assuming that everything that doesn't match the 'word' pattern is a separator):
>> 'one-way street'.split(/[^-a-zA-Z]/).size
=> 2
>> 'one-way street'.split(/[^-a-zA-Z]/).each { |m| puts m }
one-way
street
=> ["one-way", "street"]
However, there are some other symbols that can be included in the regex - for example, ' to support the words like "it's".
This is pretty simplistic but does the job if you are typing words with spaces in between. It ends up counting numbers as well but I'm sure you could edit the code to not count numbers.
puts "enter a sentence to find its word length: "
word = gets
word = word.chomp
splits = word.split(" ")
target = splits.length.to_s
puts "your sentence is " + target + " words long"
The best way to do is to use split method.
split divides a string into sub-strings based on a delimiter, returning an array of the sub-strings.
split takes two parameters, namely; pattern and limit.
pattern is the delimiter over which the string is to be split into an array.
limit specifies the number of elements in the resulting array.
For more details, refer to Ruby Documentation: Ruby String documentation
str = "This is a string"
str.split(' ').size
#output: 4
The above code splits the string wherever it finds a space and hence it give the number of words in the string which is indirectly the size of the array.
The above solution is wrong, consider the following:
"one-way street"
You will get
["one-way","", "street"]
Use
'one-way street'.gsub(/[^-a-zA-Z]/, ' ').split.size
This splits words only on ASCII whitespace chars:
p " some word\nother\tword|word".strip.split(/\s+/).size #=> 4

Resources