0

I have this array of strings.

["Anyvalue", "Total", "value:", "9,999.00", "Token", " ", "|", " ", "Total", "chain", "value:", "4,948"]

and I'm trying to get numbers in one line of code. I tried many methods but wasn't really helpful as am expecting.

I'm using one with grep method:

array.grep(/\d+/, &:to_i)  #[9, 4]

but it returns an array of first integers only. It seems like I have to add something to the pattern but I don't know what.

Or there is another way to grab these numbers in an Array?

2 Answers 2

1

you can use:

array.grep(/[\d,]+\.?\d+/)

if you want int:

array.grep(/[\d,]+\.?\d+/).map {_1.gsub(/[^0-9\.]/, '').to_i}

and a faster way (about 5X to 10X):

array.grep(/[\d,]+\.?\d+/).map { _1.delete("^0-9.").to_i }

for a data like:

%w[
,,,4
1
1.2.3.4
-2
1,2,3
9,999.00
4,948
22,956
22,536,129,336
123,456
12.]

use:

  data.grep(/^-?\d{1,3}(,\d{3})*(\.?\d+)?$/)

output:

 ["1", "-2", "9,999.00", "4,948", "22,956", "22,536,129,336", "123,456"]
Sign up to request clarification or add additional context in comments.

2 Comments

Note that [",,,4", "1", "1.2.3.4", "-2", "1,2,3"].grep(/[\d,]+\.?\d+/) #=> [",,,4", "1.2.3.4", "1,2,3"].
@CarySwoveland so, regex highly depends on your test data and what you want... if your input and output is complex, so you must use complex regex as updated part... but for what OP wanted, the regex was OK.
0
arr = ["Anyvalue", "Total", "value:", "9,999.00", "Token", " ", "61.4.5",
       "|", "chain", "-4,948", "3,25.61", "1,234,567.899"]
rgx = /\A\-?\d{1,3}(?:,\d{3})*(?:\.\d+)?\z/
arr.grep(rgx)
  #=> ["9,999.00", "-4,948", "1,234,567.899"]

Regex demo. At the link the regular expression was evaluated with the PCRE regex engine but the results are the same when Ruby's Onigmo engine is used. Also, at the link I've used the anchors ^ and $ (beginning and end of line) instead of \A and \z (beginning and end of string) in order test the regex against multiple strings.

The regular expression can be broken down as follows.

/
\A          # match the beginning of the string
\-?         # optionally match '-'
\d{1,3}     # match between 1 and 3 digits inclusively
(?:         # begin a non-capture group
  ,\d{3}    # match a comma followed by 3 digits
)*          # end the non-capture group and execute 0 or more times
(?:         # begin a non-capture group
\.\d+       # match a period followed by one or more digits
)?          # end the non-capture and make it optional
\z          # match the end of the string
/

To make the test more robust we could use the methods Kernel::Float, Kernel::Rational and Kernel::Complex, all with the optional argument :exception set to false.

arr = ["Total", "9,999.00", " ", "61.4.5", "23e4", "-234.7e-2", "1+2i",
       "3/4", "|", "chain", "-4,948", "3,25.61", "1,234,567.899", "10"]
arr.select { |s| s.match?(rxg) || Float(s, exception: false) ||
  Rational(s, exception: false) Complex(s, exception: false) }
  #=> ["9,999.00", "23e4", "-234.7e-2", "1+2i", "3/4", "-4,948",
  #    "1,234,567.899", "10"]

Note that "23e4", "-234.7e-2", "1+2i" and "3/4" are respectively the string representations of an integer, float, complex and rational number.

1 Comment

sorry, I didn't notice something, and commented based on that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.