craigeley
craigeley

Reputation: 352

Matching Against Literal String over Ruby Array

I have created an array, and I want to match it against a file. If the file does not contain array items, then I want them to be appended to the file. Here is how it looks now:

data = tasks.map { |d, e| Time.parse(d).strftime("%Y-%m-%d,%H:%M,") + "#{project}" + e.strip }
target = '/Users/username/file.csv'
info = File.read(target)
out = File.open(target, 'a')
data.each { |t| out.write("#{t}\n") if info !~ /(#{t})/ }

However, in the file evaluation /#{t} yields false positives if the array item contains special regex characters, like "(" or "[". So what happens is that those items will be written again even if they are already present in the file. How can I get around this?

Upvotes: 0

Views: 61

Answers (2)

mu is too short
mu is too short

Reputation: 434965

If you don't care about patterns, why use a regex at all? Why not use include?:

include? other_str → true or false

Returns true if str contains the given string or character.

So you could say:

data.each { |t| out.write("#{t}\n") unless info.include? t

Or you use index:

index(substring [, offset]) → fixnum or nil
index(regexp [, offset]) → fixnum or nil

Returns the index of the first occurrence of the given substring or pattern (regexp) in str. Returns nil if not found.

and say

data.each { |t| out.write("#{t}\n") unless info.index t

Upvotes: 2

Todd A. Jacobs
Todd A. Jacobs

Reputation: 84453

Use Regexp Escapes

Your post doesn't include an actual corpus, so it's impossible to tell what's really causing the problem, or what your data should look like. In future, please include such information in your question.

AS a rule of thumb, a dynamically-constructed regex should be:

  1. Anchored in your pattern.
  2. Escaped, with the Regexp#escape method.

For example, I'd probably rewrite your logic like so:

data.each { |t| out.puts t unless info =~ /#{Regexp.escape t}/ }

Sample Transformation

Just to get an idea of what the #escape method is doing under the hood, imagine that your data looks like this:

t = 'foo[^bar]'
#=> "foo[^bar]"

regex = Regexp.escape t
#=> "foo\\[\\^bar\\]"

t.match /#{regex}/
#=> #<MatchData "foo[^bar]">

The #escape method is thus allowing you to match a string with the same characters contained in your interpolated regex literal. That's actually pretty cool, and hopefully helps you out.

Upvotes: 2

Related Questions