Page 1 of 1

Why can't I start search for backslash?

Posted: Wed Jan 04, 2006 11:03 pm
by mhuggins
This is my first time attempting to use regular expressions (ereg, preg_match), so I apologize in advance for my naivety.

This line of code is resulting in an error message in my Apache logs:

Code: Select all

$str = "so then I said {tmp:loop from=\"1\" to=\"5\" step=\"1\"}";
print(ereg("\\{0}\{tmp:loop .*}", $str)."<br/>");
The error message is this:

Code: Select all

[Wed Jan 04 23:00:37 2006] [error] [client 127.0.0.1] PHP Warning:  preg_match() [<a href='function.preg-match'>function.preg-match</a>]: Delimiter must not be alphanumeric or backslash in C:\\Documents and Settings\\Matthew Huggins\\My Documents\\Programming\\matthuggins.com\\regex.php on line 4
I try changing the line of code to the following, which then works with a resulting "1" being displayed:

Code: Select all

$str = "so then I said {tmp:loop from=\"1\" to=\"5\" step=\"1\"}";
print(ereg("\{tmp:loop .*}", $str)."<br/>");

More explanation...

Posted: Thu Jan 05, 2006 1:03 am
by mhuggins
Perhaps it would help if I explain in more detail what I'm trying to do and where exactly my problem lies. I want to find certain tags in some files I host that are to the effect of {tmp:command data="value" data="value"}. It's somewhat similar to HTML tags, but will have a few modifications.

Here is what I got to work:

Code: Select all

$matches = null;
$str = "so then I said {tmp:loop from=\"1\" to=\"5\" step=\"1\"}";

preg_match("/\{tmp:.*}/", $str, $matches, PREG_OFFSET_CAPTURE);
print_r($matches);
The print_r statement results in what I expect:

Code: Select all

Array
(
    [0] => Array
        (
            [0] => {tmp:loop from="1" to="5" step="1"}
            [1] => 15
        )

)
Here is my problem. I want to only find these {tmp:.....} tags that DON'T have a backslash in front of them. I tried to accomplish this using the following code (note the added "\\{0}" to the regex), and it ended up finding no matches. What am I doing wrong?

Code: Select all

print(preg_match("/\\{0}\{tmp:.*}/", "so then I said {tmp:loop from=\"1\" to=\"5\" step=\"1\"}", $matches, PREG_OFFSET_CAPTURE)."<br/>");

Posted: Thu Jan 05, 2006 6:31 am
by Chris Corbyn
The code you posted in your first thread does not correspond with your error by the way:
PHP Warning: preg_match() [<a href='function.preg-match'>function.preg-match</a>]: Delimiter must not be alphanumeric or backslash in C:\\Documents and Settings\\Matthew Huggins\\My Documents\\Programming\\matthuggins.com\\regex.php on line 4
That refers to a preg_match() ... you posted an ereg() ;)

Read over the regex tutorials stickied at the top of this regex forum for a quick booster on using the preg_ functions :)

Posted: Thu Jan 05, 2006 10:05 am
by pickle
The error you're getting is saying your pattern doesn't have delimiters. All patterns in preg_match must start and end with the same alphanumeric character:

Code: Select all

//valid
$pattern = "/this is a pattern/";

//invalid
$pattern = "this is a pattern";

//also invalid
$pattern = "/this is a pattern";
~d11wtq is right of course - you didn't post the right regex (simple mistake) so we can't help you any further.

Posted: Thu Jan 05, 2006 11:01 am
by mhuggins
You are both right, I posted the wrong error message from the log file. It looks like the ereg() function is not logging an error, but it is also providing empty output. Either way, it does not seem to be what I am looking for.

Perhaps part of my problem is that the PHP website doesn't clearly define why I would choose ereg() over preg_match() or vice versa. I am currently attempting to use preg_match(), and the second post I made in this thread accurately represents my dilemma. I've quoted that info below.
mhuggins wrote:Perhaps it would help if I explain in more detail what I'm trying to do and where exactly my problem lies. I want to find certain tags in some files I host that are to the effect of {tmp:command data="value" data="value"}. It's somewhat similar to HTML tags, but will have a few modifications.

Here is what I got to work:

Code: Select all

$matches = null;
$str = "so then I said {tmp:loop from="1" to="5" step="1"}";

preg_match("/\{tmp:.*}/", $str, $matches, PREG_OFFSET_CAPTURE);
print_r($matches);
The print_r statement results in what I expect:

Code: Select all

Array
(
    [0] => Array
        (
            [0] => {tmp:loop from="1" to="5" step="1"}
            [1] => 15
        )

)
Here is my problem. I want to only find these {tmp:.....} tags that DON'T have a backslash in front of them. I tried to accomplish this using the following code (note the added "\\{0}" to the regex), and it ended up finding no matches. What am I doing wrong?

Code: Select all

print(preg_match("/\\{0}\{tmp:.*}/", "so then I said {tmp:loop from="1" to="5" step="1"}", $matches, PREG_OFFSET_CAPTURE)."<br/>");

Another question

Posted: Thu Jan 05, 2006 11:30 am
by mhuggins
Another question I have is this. I've changed my code to the following so that I can match opening tags (such as {tmp:loop...}), as well as closing tags (such as {/tmp:loop}). For some reason my regex is not distinguishing between two separate tags I have. See the code below:

Code: Select all

$matches = null;
$str = "{tmp:loop from=\"1\" to=\"5\" step=\"1\"}test{/tmp:loop}";
preg_match_all("#\{/?tmp:.*}#i", $str, $matches, PREG_OFFSET_CAPTURE);
print_r($matches);
Here is the output. Note that both the opening and closing tags are lumped into one match.

Code: Select all

Array
(
    [0] => Array
        (
            [0] => Array
                (
                    [0] => {tmp:loop from="1" to="5" step="1"}test{/tmp:loop}
                    [1] => 0
                )
        )
)
Here is what I am trying to get the output to be (my arrays may be off a bit since I've never used this function before, sorry!):

Code: Select all

Array
(
    [0] => Array
        (
            [0] => Array
                (
                    [0] => {tmp:loop from="1" to="5" step="1"}
                    [1] => 0
                )
            [1] => Array
                (
                    [0] => {/tmp:loop}
                    [1] => 39
                )
        )
)

Posted: Thu Jan 05, 2006 11:38 am
by Chris Corbyn
Change ".*" to ".*?" .* is greedy :)

As for when to use preg_ over ereg_ .... *always* IMHO. Preg has a thorough documentation at the perl website and it's faster/more powerful/more compact ;)

Posted: Thu Jan 05, 2006 12:32 pm
by mhuggins
d11wtq wrote:Change ".*" to ".*?" .* is greedy :)
Wow, that totally fixed my problem. I'm not sure I understand why this fixed it, though.

As I interpret it, I originally had it looking for "any character zero or more times". With what you suggested I change it to, I now interpret it as "any character zero or more times, zero or one times".

I guess I just don't understand the logic behind the change from ".*" to ".*?" and how the interpreter understands this to mean what I am looking for. Can you help to explain it a little, or point me to some documentation that might already exist?

Thanks so much for the help!!

Posted: Thu Jan 05, 2006 12:46 pm
by feyd
there are several threads that talk about what the difference is between .* and .*? and what the ? does to a pattern.. Search for ungreedy with me, feyd, as the author.