Go Back   vb.org Archive > vBulletin 3 Discussion > vB3 Programming Discussions
FAQ Community Calendar Today's Posts Search

Reply
 
Thread Tools Display Modes
  #1  
Old 08-17-2012, 02:43 PM
m002.p's Avatar
m002.p m002.p is offline
 
Join Date: Jan 2007
Location: Worcester
Posts: 240
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default Using preg_match_all...

Hi everyone,

I have a string for example like below:

Code:
id:3,name:example,ip:89.12.4.54,sa:false,a:false;id:5,name:exampletwo,ip:78.23.45.61,sa:false,a:true;
I am using a preg_match_all function to retrieve the string pattern into variables.

However, the following doesnt seem to work properly. It works when there is one of the pattern but if more than one the array is created incorrectly.

I am inexperienced with preg_match_all, anyone spot how to just isolate the pattern correctly?

My code:

Code:
// Get array
function get_vars($var)
{
	$vars = array();
	$pattern = "/id:(.*),name:(.*),ip:(.*),sa:(.*),a:(.*);/si"; // This is the pattern to retrieve in the string

	if (preg_match_all ($pattern , $var, $matches, PREG_SET_ORDER))
	{
		foreach ($matches as $var)
		{
			$vars[] = array 
					(
						'id'		=> $var[1],
						'name'		=> htmlspecialchars_decode(trim($var[2])),
						'ip'		=> $var[3],
						'sa'		=> $var[4],
						'a'		=> $var[5]
					);
		}
	}
	return $vars;
}
Any help most appreciated.

Matt
Reply With Quote
  #2  
Old 08-17-2012, 03:22 PM
kh99 kh99 is offline
 
Join Date: Aug 2009
Location: Maine
Posts: 13,185
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

The problem is that the * is "greedy" by default, so it will match as much as possible. That's making the first id.*) match all the way to the name: in the last record (because at least one match of that is needed to complete the pattern). You can make the * non-greedy by putting a ? after it, so a pattern like this seems to work:

Code:
$pattern = "/id:(.*?),name:(.*?),ip:(.*?),sa:(.*?),a:(.*?);/si";


Edit: you can also make all matches "ungreedy" by adding the "U" modifier, so this also works:
Code:
$pattern = "/id:(.*),name:(.*),ip:(.*),sa:(.*),a:(.*);/siU";
Reply With Quote
  #3  
Old 08-25-2012, 09:50 AM
m002.p's Avatar
m002.p m002.p is offline
 
Join Date: Jan 2007
Location: Worcester
Posts: 240
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Ah thanks, works a treat. On a similar note, furthering this issue, could you explain the following to me?

I get this message while using preg_match:

Code:
PHP Warning:  preg_match() [<a href='function.preg-match'>function.preg-match</a>]: Compilation failed: unmatched parentheses at offset 20
I do not understand it; the code examples used are:

Code:
if (preg_match("/\b{$console['chat']}\b/", 'BOT call'))
The above may not be the source of that error but I know for certain that if $console['chat'] was a value of "..." (without quotes), it matches as true? How "..." translates as "BOT call" is beyond me there.

Code:
if (preg_match("/{$ctag}/", $player['name']))
This one always returns true when $ctag = "|SOG|" (without quotes) and the $player['name'] variable contains anything eg. "Matt" or "Tom"... dont understand what is wrong there.

Code:
if (preg_match("/\b{$disresult['names']}\b/", $player['name']))
Lastly not sure if this one is causing the php error but although it appears to work, maybe I am using the wrong context? This example is used within a while mysql_fetch_array query for the variable $disresult['names'].

Is it best I used strpos() instead?
Reply With Quote
  #4  
Old 08-25-2012, 12:08 PM
kh99 kh99 is offline
 
Join Date: Aug 2009
Location: Maine
Posts: 13,185
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

I think all your issues have to do with special (meta) characters. Some of the character that are included in your variables have special meaning when in a preg pattern. For instance, and "." means "match any character". You probably know that "\b" means match a word boundary, so when $console['chat'] = "...", the pattern says "match any 3 character word", so it's probably matching "BOT". In the second one you mention, '|' has a special meaning. If you want to know more, it's all explained here: http://us2.php.net/manual/en/referen...ern.syntax.php

You could solve that by using the function preg_quote(), which makes sure that any special characters are 'escaped'. So for instance, your first example would be:
Code:
if (preg_match('/\b{' . preg_quote($console['chat'], '/') . '}\b/', 'BOT call'))

I left in the { and } chars, I don't know if you want to match those or if they were just there to surround the variable. If you don't want them to match something, then you should take them out (they have another special meaning in patterns, and aren't used to enclose variables).


However, like you mentioned, if you have no need of the "power" of the preg functions, you should use strpos or something like that. I notice that a couple of your patterns have "\b" - if it's important that you only match the separate word (and if it could be at the start or end so it may or may not have a space before and after it), then you may need a preg function. It's hard to say without knowing exactly what you're doing.
Reply With Quote
  #5  
Old 08-25-2012, 12:22 PM
m002.p's Avatar
m002.p m002.p is offline
 
Join Date: Jan 2007
Location: Worcester
Posts: 240
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

I was using the { } characters to enclose the variable as I have done in a mysql query for any variables like $array['offset'];

Do you not need to enclose variables? Is there documentation to understand when and when not to enclose in either ".$var['name']." or {$var['name']} ?

I thought \b meant exact word search? So for example "I have a string" passed through preg_match with this \b searching for "in" would be false, whereas without the \b it would be true?

Lastly what is the syntax for the above preg_quote example you provided without the \b?

Code:
if (preg_match('/' . preg_quote($player['name'], '/') . '/', $ctag))
?

Thanks so much for your help, I am learning alot about preg_match. I was always used to ereg before it died in PHP 5
Reply With Quote
  #6  
Old 08-25-2012, 12:41 PM
kh99 kh99 is offline
 
Join Date: Aug 2009
Location: Maine
Posts: 13,185
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Quote:
Originally Posted by m002.p View Post
I was using the { } characters to enclose the variable as I have done in a mysql query for any variables like $array['offset'];

Do you not need to enclose variables? Is there documentation to understand when and when not to enclose in either ".$var['name']." or {$var['name']} ?
Oh right, I was getting confused. You do sometimes need those like you said (and they don't hurt even if you don't technically need them - although I think you did need them, like you said). So you would want to take them out of my example since the variable isn't directly in the string any more.

Quote:
I thought \b meant exact word search? So for example "I have a string" passed through preg_match with this \b searching for "in" would be false, whereas without the \b it would be true?
That's pretty much the idea, yeah. Sorry, I wasn't sure how much you knew about it. Sometimes people just copy stuff from somewhere else and don't really understand it.


Quote:
Lastly what is the syntax for the above preg_quote example you provided without the \b?

Code:
if (preg_match('/' . preg_quote($player['name'], '/') . '/', $ctag))
?
That looks right.
Reply With Quote
  #7  
Old 08-25-2012, 12:51 PM
m002.p's Avatar
m002.p m002.p is offline
 
Join Date: Jan 2007
Location: Worcester
Posts: 240
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Thanks.

So finally, is it best to use the ". instead of {} for variables directly in the preg_match function to avoid the {} being used as part of the search critera?
Reply With Quote
  #8  
Old 08-25-2012, 01:11 PM
kh99 kh99 is offline
 
Join Date: Aug 2009
Location: Maine
Posts: 13,185
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Quote:
Originally Posted by m002.p View Post
Thanks.

So finally, is it best to use the ". instead of {} for variables directly in the preg_match function to avoid the {} being used as part of the search critera?
Well, no. It was my mistake - the {} was necessary around the variable name in your original string, and would really be part of the variable name and not part of the pattern, so that was OK. The only issue is that you have to put the variable through preg_quote() unless you're sure it won't contain any meta-characters (unless the variable actually contained a pattern, of course). You could instead do this if you prefered:

Code:
$console['chat'] = preg_quote($console['chat'], '/');
if (preg_match("/\b{$console['chat']}\b/", 'BOT call'))
Reply With Quote
  #9  
Old 08-26-2012, 08:29 AM
m002.p's Avatar
m002.p m002.p is offline
 
Join Date: Jan 2007
Location: Worcester
Posts: 240
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Kh99,

I have one preg_match I simply cannot get to work as true in this if statement.

Any ideas?

Code:
		// Check for player reports
		$p1 = "/BOT report (.*);(.*)/";
		if (preg_match_all($p1, $console['chat'], $out1))
		{
                        // Do Something
                 }
The $console['chat'] variable as the input contains "BOT report 0;" or "BOT report 0;reason" and for both instances the if statement never works. Lost here...
Reply With Quote
  #10  
Old 08-26-2012, 01:27 PM
kh99 kh99 is offline
 
Join Date: Aug 2009
Location: Maine
Posts: 13,185
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

It looks right to me, and this test program seems to work:

Code:
<?php
$str = "BOT report 0;" or "BOT report 0;reason";
$p1 = "/BOT report (.*);(.*)/";
if (preg_match_all($p1, $str, $out1))
{
   echo "<pre>";
   print_r($out1);
   echo "</pre>";
}
else
    echo "No match";

$str = "BOT report 0;reason";
if (preg_match_all($p1, $str, $out1))
{
   echo "<pre>";
   print_r($out1);
   echo "</pre>";
}
else
    echo "No match";

Are you sure that's exactly what's in $console['chat']? For instance, is there just one space between the words (and not tabs or anything)?
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT. The time now is 03:04 PM.


Powered by vBulletin® Version 3.8.12 by vBS
Copyright ©2000 - 2025, vBulletin Solutions Inc.
X vBulletin 3.8.12 by vBS Debug Information
  • Page Generation 0.10897 seconds
  • Memory Usage 2,280KB
  • Queries Executed 13 (?)
More Information
Template Usage:
  • (1)SHOWTHREAD
  • (1)ad_footer_end
  • (1)ad_footer_start
  • (1)ad_header_end
  • (1)ad_header_logo
  • (1)ad_navbar_below
  • (1)ad_showthread_beforeqr
  • (1)ad_showthread_firstpost
  • (1)ad_showthread_firstpost_sig
  • (1)ad_showthread_firstpost_start
  • (14)bbcode_code
  • (4)bbcode_quote
  • (1)footer
  • (1)forumjump
  • (1)forumrules
  • (1)gobutton
  • (1)header
  • (1)headinclude
  • (1)navbar
  • (3)navbar_link
  • (120)option
  • (1)pagenav
  • (1)pagenav_curpage
  • (1)pagenav_pagelink
  • (10)post_thanks_box
  • (10)post_thanks_button
  • (1)post_thanks_javascript
  • (1)post_thanks_navbar_search
  • (10)post_thanks_postbit_info
  • (10)postbit
  • (10)postbit_onlinestatus
  • (10)postbit_wrapper
  • (1)spacer_close
  • (1)spacer_open
  • (1)tagbit_wrapper 

Phrase Groups Available:
  • global
  • inlinemod
  • postbit
  • posting
  • reputationlevel
  • showthread
Included Files:
  • ./showthread.php
  • ./global.php
  • ./includes/init.php
  • ./includes/class_core.php
  • ./includes/config.php
  • ./includes/functions.php
  • ./includes/class_hook.php
  • ./includes/modsystem_functions.php
  • ./includes/functions_bigthree.php
  • ./includes/class_postbit.php
  • ./includes/class_bbcode.php
  • ./includes/functions_reputation.php
  • ./includes/functions_post_thanks.php 

Hooks Called:
  • init_startup
  • init_startup_session_setup_start
  • init_startup_session_setup_complete
  • cache_permissions
  • fetch_postinfo_query
  • fetch_postinfo
  • fetch_threadinfo_query
  • fetch_threadinfo
  • fetch_foruminfo
  • style_fetch
  • cache_templates
  • global_start
  • parse_templates
  • global_setup_complete
  • showthread_start
  • showthread_getinfo
  • forumjump
  • showthread_post_start
  • showthread_query_postids
  • showthread_query
  • bbcode_fetch_tags
  • bbcode_create
  • showthread_postbit_create
  • postbit_factory
  • postbit_display_start
  • post_thanks_function_post_thanks_off_start
  • post_thanks_function_post_thanks_off_end
  • post_thanks_function_fetch_thanks_start
  • post_thanks_function_fetch_thanks_end
  • post_thanks_function_thanked_already_start
  • post_thanks_function_thanked_already_end
  • fetch_musername
  • postbit_imicons
  • bbcode_parse_start
  • bbcode_parse_complete_precache
  • bbcode_parse_complete
  • postbit_display_complete
  • post_thanks_function_can_thank_this_post_start
  • pagenav_page
  • pagenav_complete
  • tag_fetchbit_complete
  • forumrules
  • navbits
  • navbits_complete
  • showthread_complete