13 Replies - 521 Views - Last Post: 30 November 2017 - 10:18 AM Rate Topic: -----

#1 JeremyBenson11   User is offline

  • D.I.C Regular

Reputation: 2
  • View blog
  • Posts: 270
  • Joined: 10-January 14

Regex Optional Non Capture

Posted 21 November 2017 - 06:18 AM

Hello,

Can anyone help me with optional non capture groups in php regex? I had some code from a C# project I was helped with, but can't convert.

$string = ltrim($this->text, '<');
      $string = rtrim($this->text, '>');
      $string = trim($string);
													
      $matches = array();
     preg_match_all(
		'/(?:put|place) (?:the)? (?<subject>.+) in (?:the)? (?<container>.+)/',
		$string,
	        $matches,
	        PREG_PATTERN_ORDER
		);
							
     var_dump($matches);


I get empty results unless I include "the" in each optional group.

Thanks for any help.

This post has been edited by JeremyBenson11: 21 November 2017 - 06:22 AM


Is This A Good Question/Topic? 0
  • +

Replies To: Regex Optional Non Capture

#2 andrewsw   User is offline

  • RequestedRangeNotSatisfiable
  • member icon

Reputation: 6561
  • View blog
  • Posts: 26,607
  • Joined: 12-December 12

Re: Regex Optional Non Capture

Posted 21 November 2017 - 08:00 AM

I think it would help if you provided sample input, and both versions of the regex (one that works and one that doesn't).
Was This Post Helpful? 0
  • +
  • -

#3 JeremyBenson11   User is offline

  • D.I.C Regular

Reputation: 2
  • View blog
  • Posts: 270
  • Joined: 10-January 14

Re: Regex Optional Non Capture

Posted 22 November 2017 - 10:26 AM

The supplied code works:

/(?:put|place) (?:the)? (?<subject>.+) in (?:the)? (?<container>.+)/


It just doesn't work the way I thought it should. It will only match if the optional the's are supplied, and only works with put, instead of place..

put the wood in the fire: returns wood and fire

place the wood in the fire (doesn't work)

put wood in fire (doesn't work)

This post has been edited by JeremyBenson11: 22 November 2017 - 10:27 AM

Was This Post Helpful? 0
  • +
  • -

#4 andrewsw   User is offline

  • RequestedRangeNotSatisfiable
  • member icon

Reputation: 6561
  • View blog
  • Posts: 26,607
  • Joined: 12-December 12

Re: Regex Optional Non Capture

Posted 22 November 2017 - 01:21 PM

How are you searching the three expressions? Individually, line by line? If they are all part of a single block of text, is it only the first one that works? In which case, it would be to do with the application of a global search, across multiple lines, that is problematic.

But, as I first suspected, it is also to do with spaces. If 'the' is missing you won't have two spaces between the first and third word.

One approach:
(?:put|place) (?:the )?(?<subject>.+) in (?:the )?(?<container>.+)

That is, recognising that the word 'the' will always introduce an additional space.
Was This Post Helpful? 0
  • +
  • -

#5 JeremyBenson11   User is offline

  • D.I.C Regular

Reputation: 2
  • View blog
  • Posts: 270
  • Joined: 10-January 14

Re: Regex Optional Non Capture

Posted 26 November 2017 - 08:05 AM

Sweet, thanks, you're dead on with that, but: (?:put|place) is only working with "put".
Was This Post Helpful? 0
  • +
  • -

#6 andrewsw   User is offline

  • RequestedRangeNotSatisfiable
  • member icon

Reputation: 6561
  • View blog
  • Posts: 26,607
  • Joined: 12-December 12

Re: Regex Optional Non Capture

Posted 26 November 2017 - 08:24 AM

It works for my made-up testing. Provide some input and explain how you are applying your code.
Was This Post Helpful? 0
  • +
  • -

#7 JeremyBenson11   User is offline

  • D.I.C Regular

Reputation: 2
  • View blog
  • Posts: 270
  • Joined: 10-January 14

Re: Regex Optional Non Capture

Posted 28 November 2017 - 08:44 AM

Ok, here's the code to process the input:

$string = ltrim($this->text, '<');
							$string = rtrim($this->text, '>');
							$string = trim($string);
													
							$matches = array();
							preg_match_all(
											'/(?:put|place) (?:the )?(?<subject>.+) in (?:the )?(?<container>.+)/',
											$string,
											$matches,
											PREG_PATTERN_ORDER
							);
																
							if(!empty($matches['subject']))
							{
								
								if($matches['container'][0] == 'fire' || $matches['container'][0] == 'fire pit' || $matches['container'][0] == 'firepit')
								{
									
										// put item in fire pit
									   
										$return = $action->put_in_fire($character, $matches['subject'][0]);
										
										// end put item in fire pit
								}else{
									
									// put item in container
									
										$return = $action->put_in_container($character, $matches['subject'][0], $matches['container'][0]);
									
									// end put item in container
								}
								
							}else{
								
								preg_match_all(
											'/(?:put|place) (?:the )?(?<subject>.+) on (?:the )?(?<surface>.+)/',
											$string,
											$matches,
											PREG_PATTERN_ORDER
								);
								
								if($matches['subject'] !== '')
								{
									
									
									
								}else{
									
									// error, no matches found to put command
									
								}
								
							}
							
							if(empty($return) || !isset($return))
							{
								
								$return['messageType'] = 'icon';
								$return['icon'] = 'hazard';
								$return['message'] = 'Sorry, can\'t figure out the command.';
 								
							}



input is:

<place oil can in leather knapsack>

output is:

undefined variable return CommandParser.php line 493

return is defined by a found match in the code.

Don't worry about angle brackets. They're removed before parsing. Angle brackets determine game commands from chat room text. The game blends free form role playing and mud rpg into a IRC chat client style game with interface and light rules. Basically table top meets IRC freeform.

This post has been edited by JeremyBenson11: 28 November 2017 - 08:48 AM

Was This Post Helpful? 0
  • +
  • -

#8 andrewsw   User is offline

  • RequestedRangeNotSatisfiable
  • member icon

Reputation: 6561
  • View blog
  • Posts: 26,607
  • Joined: 12-December 12

Re: Regex Optional Non Capture

Posted 28 November 2017 - 09:21 AM

If you are receiving an error then that is not the same as the regex not working.

To receive help to resolve your error quote the exact error details and confirm which line they refer to in your posted code.

"place oil can in leather knapsack" This is different to the examples you first provided ;)
Was This Post Helpful? 0
  • +
  • -

#9 JeremyBenson11   User is offline

  • D.I.C Regular

Reputation: 2
  • View blog
  • Posts: 270
  • Joined: 10-January 14

Re: Regex Optional Non Capture

Posted 28 November 2017 - 10:53 AM

You're missunderstanding. It's regex capture groups:

"put the wood in the fire" is the same as "put the oil can in the leather knapsack"

That's the point of the put in regex command we're working on:

'/(?:put|place) (?:the )?(?<subject>.+) in (?:the )?(?<container>.+)/'

The undefined return is caused by this regex not working when it should, or else we would get return defined here:

$matches = array();
	preg_match_all(
		'/(?:put|place) (?:the )?(?<subject>.+) in (?:the )?(?<container>.+)/',
	         $string,
	         $matches,
		PREG_PATTERN_ORDER
	);


There is absolutely no difference between "put wood in fire" and "put oil can in leather knapsack", not as far as the code is concerned. It's looking for a put in command, it doesn't care what the item or container is.

Since the container is not fire we should hit this line of code:

else{
									
	// put item in container
									
       $return = $action->put_in_container($character, $matches['subject'][0], $matches['container'][0]);
									
	// end put item in container
								
}



however, the original regex is failing its purpose. Nothing shows up here:

if(!empty($matches['subject']))


So we end up here:

else{
								
								preg_match_all(
											'/(?:put|place) (?:the )?(?<subject>.+) on (?:the )?(?<surface>.+)/',
											$string,
											$matches,
											PREG_PATTERN_ORDER
								);
								
								if($matches['subject'] !== '')
								{
									
									
									
								}else{
									
									// error, no matches found to put command
									
								}
								
							}


Which doesn't define return, because it's an incomplete new test.

The regex is not matching with place, only put.

<put the wood in the fire> - works
<put the oil can in the leather knapsack> - works
<place the oil can in the leather knapsack> - does not work in the regex

It's a simple error, but I don't understand what's causing it. You say place and put are working for you, but it's not with this:

preg_match_all(
               '/(?:put|place) (?:the )?(?<subject>.+) in (?:the )?(?<container>.+)/',
	       $string,
	       $matches,
	       PREG_PATTERN_ORDER
	);

This post has been edited by JeremyBenson11: 28 November 2017 - 10:54 AM

Was This Post Helpful? 0
  • +
  • -

#10 ArtificialSoldier   User is offline

  • D.I.C Lover
  • member icon

Reputation: 2040
  • View blog
  • Posts: 6,256
  • Joined: 15-January 14

Re: Regex Optional Non Capture

Posted 28 November 2017 - 11:21 AM

Quote

The undefined return is caused by this regex not working when it should, or else we would get return defined here:

Well, technically the undefined error is caused because your code does not account for the case when the pattern does not match, or it makes other incorrect assumptions. You should add code to check for that. In fact, in the case where the subject or container is not accounted for in your code, you should print all of that out so you can actually get some feedback from your code other than an undefined variable error.

Quote

It's a simple error, but I don't understand what's causing it. You say place and put are working for you, but it's not with this:

Yes, that does work. Verify for yourself here:

http://www.phpliveregex.com

Enter your pattern, your search string, and watch it match. The regex is not the problem, your code is the problem.
Was This Post Helpful? 1
  • +
  • -

#11 JeremyBenson11   User is offline

  • D.I.C Regular

Reputation: 2
  • View blog
  • Posts: 270
  • Joined: 10-January 14

Re: Regex Optional Non Capture

Posted 29 November 2017 - 05:31 PM

Man, you guys are slow.

"Well, technically the undefined error is caused because your code does not account for the case when the pattern does not match"

YES, it does. When it doesn't match it goes here.

else{
								
								preg_match_all(
											'/(?:put|place) (?:the )?(?<subject>.+) on (?:the )?(?<surface>.+)/',
											$string,
											$matches,
											PREG_PATTERN_ORDER
								);
								
								if($matches['subject'] !== '')
								{
									
									
									
								}else{
									
									// error, no matches found to put command
									
								}
								
							}



Right there. There's nothing there defining the variable $return, because I haven't got to that regex yet, it's redundant.

That else should never be hit when entering

<place the oil can in the leather knapsack>

hence the reason for the thread. Like I said, it's the regex.

There is no logical reason other than a regex problem for two strings that should match not working.

<place the oil can in the leather knapsack> - does not work.

<put the oil can in the leather knapsack> - works.

Trust me, I know, I'm typing the input.

This post has been edited by JeremyBenson11: 29 November 2017 - 05:33 PM

Was This Post Helpful? 0
  • +
  • -

#12 ArtificialSoldier   User is offline

  • D.I.C Lover
  • member icon

Reputation: 2040
  • View blog
  • Posts: 6,256
  • Joined: 15-January 14

Re: Regex Optional Non Capture

Posted 29 November 2017 - 05:41 PM

I don't consider an empty else block as error handling.

Quote

hence the reason for the thread. Like I said, it's the regex.

Then explain why the regex matches the input you provide on that test site. Just try it, man. Click on that link in my previous post. In the "Regex" box on the top, paste this:

(?:put|place) (?:the )?(?<subject>.+) in (?:the )?(?<surface>.+)


In the "Your search strings" box, paste this:

place the oil can in the leather knapsack


Notice that it matches. So, why are you going to make assertions like this:

Quote

There is no logical reason other than a regex problem

That is an incorrect assumption. You are not doing enough error checking and you are not doing enough debugging to print out, for example, the matches array to see exactly what is being returned. You're making assumptions based on a bunch of empty if and else blocks, and I don't know how you even make assumptions based on empty blocks of code. This is aside from the point that, if it matches, $matches['subject'] will be an array, not a string, but for some reason you're trying to do a strict comparison with a string. You should be using count and isset to check things before you start making assumptions about things that are working fine.

Quote

Trust me, I know, I'm typing the input.

That's how you start following the wrong path. Incorrect assumptions. If you knew what the problem was then you would fix it. If you don't know what the problem is, throw out your assumptions and start verifying.
Was This Post Helpful? 0
  • +
  • -

#13 JeremyBenson11   User is offline

  • D.I.C Regular

Reputation: 2
  • View blog
  • Posts: 270
  • Joined: 10-January 14

Re: Regex Optional Non Capture

Posted 29 November 2017 - 06:35 PM

HAHA, I'm slow, sorry guys. I found the error. I apologize, I was sure you guys were dead wrong. It's my initial case.

	$explode = explode('<', $this->text);
        $explode2 = explode('>', $explode[1]);
	$explode3 = explode(' ', $explode2[0]);
								
	switch($explode3[0])
	{
          case 'put':

          break;
        }



I'm going to need a place case, unless there is a way to combine two cases into one.
Was This Post Helpful? 0
  • +
  • -

#14 ArtificialSoldier   User is offline

  • D.I.C Lover
  • member icon

Reputation: 2040
  • View blog
  • Posts: 6,256
  • Joined: 15-January 14

Re: Regex Optional Non Capture

Posted 30 November 2017 - 10:18 AM

If the problem is in a part of the code that wasn't posted that does make it more difficult for us to identify the problem. That goes back to making assumptions though, you can waste a lot of time with code if you're making the wrong assumptions. It's too easy to have the code print everything out and verify everything you're doing instead of needing to make assumptions.

You can have multiple case statements before a block of code. Once it reaches a matching case statement it will continue to execute until it reaches a break line. So you can have multiple case statements before a break.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1