0

I'd like to get anything between A=[ and first enclosing ]:

> str = "Hello A=[apple] B=[boy] World"
> str.match(/A=\[(.+?)\]/)[1]
 => "apple" 

So far so good.

However, for A=[]:

> str = "Hello A=[] B=[boy] World"
> str.match(/A=\[(.+?)\]/)[1]
 => "] B=[boy" 

How can I get a empty string "", instead of "] B=[boy"?

2 Answers 2

4

Use .*? rather than .+?. The former matches zero or more characters, while the latter matches one or more.

"Hello A=[] B=[boy] World".match(/A*=*\[(.*?)\]/)[1] # => ""
1
  • Ah! How can I forget that? ;)
    – ohho
    Commented Jul 9, 2013 at 8:52
3

I'd use:

str = "Hello A=[apple] B=[boy] World"
str[/A=\[(.*?)\]/, 1] # => "apple"
str = "Hello A=[] B=[boy] World"
str[/A=\[(.*?)\]/, 1] # => ""

I'm not sure why you're using A*=*, because it means "zero or more 'A' followed by zero or more '='" and basically fails to do anything useful, and, in fact, actually opens up a hole to return bad results. See the additional information in the edit below.

Here are variations on the same themes. All are documented in the Regexp and String.[] documentation:

str = "Hello A=[apple] B=[boy] World"
str[/A=\[(.*?)\]/, 1] # => "apple"

/A=\[(.*?)\]/ =~ str 
$1 # => "apple"

str =~ /A=\[(.*?)\]/
$1 # => "apple"

/A=\[(?<in_brackets>.*?)\]/ =~ str
in_brackets # => "apple"

str = "Hello A=[] B=[boy] World"
str[/A=\[(.*?)\]/, 1] # => ""

/A=\[(.*?)\]/ =~ str 
$1 # => ""

/A=\[(?<in_brackets>.*?)\]/ =~ str 
in_brackets # => ""

the = was intended to match possible space characters before or after the equal sign, e.g. str = "Hello A= [] B=[boy] World"

Well, *=* isn't how you should do it. You need to tell the regex engine what is optional:

/A *= */

would be correct, as would:

/A ?= ?/

Here's some tests to show you what's happening:

str = "Hello [foo] A = [apple] B=[boy] World"
str[/A*=*\[(.*?)\]/, 1] # => "foo"
str[/A *=*\[(.*?)\]/, 1] # => nil
str[/A *= *\[(.*?)\]/, 1] # => "apple"
str[/A ?= ?\[(.*?)\]/, 1] # => "apple"

Notice that your pattern /A*=*/ allows the engine to match [foo], not A = [apple]. This is because you're telling it to match no A and no = as an option, which opens the hole to grab [foo]. As long as your inputs are exactly two options, with no preceding value inside brackets you'll be safe. If you have an input with that your result will be wrong.


str[/A.*=.*\[(.*?)\]/,1]?

Nope:

str = "Hello A=[apple] B=[boy] World"
str[/A.*=.*\[(.*?)\]/,1] # => "boy"

I'd recommend exploring how to use regex via Rubular. Here's a link showing the above example and why it fails.

4
  • the square bracket syntax is nice looking.
    – ohho
    Commented Jul 9, 2013 at 8:54
  • the *=* was intended to match possible space characters before or after the equal sign, e.g. str = "Hello A= [] B=[boy] World".
    – ohho
    Commented Jul 9, 2013 at 8:57
  • Then you should document those in your example strings. And, A*=* won't work for possible spaces so any answer using them will be wrong. See the edit in my answer for an explanation. Commented Jul 9, 2013 at 9:19
  • Thanks for the /A *= */ fix. I've edited the question to clarify it.
    – ohho
    Commented Jul 9, 2013 at 9:28

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.