Jump to content

Please help, tab everything inbetween brackets?


Jason28

Recommended Posts

I have spent hours trying to figure this out so I really hope you can make it work.  I would imagine it is not that hard?  I would like PHP to detect everything, spaces, tabs, letters, numbers, symbols, everything within brackets and tab them.  So that an example:

 

if($surl1 == "") 
{
// blah blah
$surl1 = "http://";
}
while($row=mysql_fetch_array($result) 
{
echo $row['name']; 
}

 

would be converted into:

 

if($surl1 == "") 
{
    // blah blah
    $surl1 = "http://";
}
while($row=mysql_fetch_array($result) 
{
    echo $row['name']; 
}

 

Please this has to be possible?  I am really stressing and trying to make it work but I suck at Regex.  Someone said use this:

 

$string = preg_replace('#\{.*?\}#s', "/t", $string); 

 

but it doesn't work for me and it doesn't look correct, especially with just the \t there shouldn't there be a $1 or something in there too?  Maybe it does work with further tweaking?

 

 

 

Link to comment
Share on other sites

You can't do this with just one expression. You need two. And some recursion.

 

First regex grabs everything between sets of {}s. It needs to be recursive so it will match up {{}} properly.

/\{(([^{}]*|(?R))*)\}/

Ignore the braces - just work with $1. The second regex applies one level of indentation.

/^\s*\S/m => \t$0

The recursion is to start the process again on what you just found.

 

Two tips:

- Put this stuff into a function so you can call it recursively

- Use preg_replace_callback and a closure/anonymous function (or just a regular function) for the first expression

- Realize that your Allman formatting and indentation style makes things quite a bit easier

 

Test your stuff on

if ($condition)
{
if ($other_condition)
{
do_something();
}
else
{
do_something_else();
}
}

Link to comment
Share on other sites

Thank you so much for your reply.  Please do not get mad at me, but you are way smarter than me and I have no idea how to write out what you just said.  Do you want me to do this?

 

function blah($var)
{
    $var = preg_replace_callback('/\{(([^{}]*|(?R))*)\}/', "$1", $var);
    $var = preg_replace_callback('/^\s*\S/m => \t$0', "$1", $var); 

   return $var; 
}

 

Sorry I do not speak the regex lingo and I tried reading tutorials but all they do is give me a migraine and when I think I understand it and put it to the test they do not work.  It would be great if you could show me the code to use please that would really make my week.  BTW all of this code appears in a text format as I am submitting it using a $_POST form and going to copy the result and paste it into my php files.

Link to comment
Share on other sites

Sorry I do not speak the regex lingo and I tried reading tutorials but all they do is give me a migraine and when I think I understand it and put it to the test they do not work.  It would be great if you could show me the code to use please that would really make my week.  BTW all of this code appears in a text format as I am submitting it using a $_POST form and going to copy the result and paste it into my php files.

 

Regex's are difficult.  I highly recommend getting your hands on an interactive testing tool.  I use http://weitz.de/regex-coach/  but there are many others you will find if you do a google for "mac interactive regex tool" as an example.

 

 

 

Link to comment
Share on other sites

Note: You'll need PHP 5.3+ for the code I'm posting. If you don't have that then say something. Or upgrade :)

 

preg_replace_callback() will execute a function and use whatever that returns as the replacement string. Compare that with preg_replace()* which only allows you to give the same replacement string for everything.

For example, you could use it to do something special with whatever text was found. You could make a BBCode tag like "[date]Y-m-d[/date]" that inserts a date according to PHP's date:

$before = "[date]Y-m-d[/date]";
$after = preg_replace_callback('#\[date\]([a-z0-9/:-]+)\[/date\]#i', function($matches) {
// $matches[1] is the format
return date($matches[1]);
}, $before);

Basically, you can execute whatever code you want.

 

In the spirit of learning, here's everything I said:

function indent($code) {
// first find all the sets of code blocks
$formatted = preg_replace_callback('/\{(([^{}]*|(?R))*)\}/', function($matches) {
	// now we're replacing them
	// $matches[0] is the entire code block unformatted
	// $matches[1] is just the code inside
	$innercode = $matches[1];

	// apply indentation
	$innercode = preg_replace('/^[ \t]*\S/m', "\t\$0", $innercode);

	// then apply indentation to any code blocks inside this one
	$innercode = indent($innercode);

	// return. don't forget to add the {}s back
	return "{" . $innercode . "}";
}, $code);
return $formatted;
}

// test
$code = if (\$condition)
{
if (\$other_condition)
{
do_something();
}
else
{
do_something_else();
}
}
PHP;

echo indent($code);

if ($condition)
{
        if ($other_condition)
        {
                do_something();
        }
        else
        {
                do_something_else();
        }
}

 

There is one difference: the second expression I posted (for adding indentation) should have [ \t] instead of \s.

 

* Without /e.

Link to comment
Share on other sites

Yeah I use hostgator and it looks like I am using PHP 5.2.17 and I get the error:

 

Parse error: syntax error, unexpected T_FUNCTION

 

with this line:

 

$formatted = preg_replace_callback('/\{(([^{}]*|(?R))*)\}/', function($matches) {

 

It also looks like it will error on this part too:

 

 

}, $code);

 

 

Link to comment
Share on other sites

Ok, interesting Hostgator told me to add a couple of lines of code to my htaccess to activate version 5.3.6 and that is the version it is using now.  The error went away, but I am dead tired as I haven't been to sleep yet so I will test it out when I wake up. I do notice that you use:

 

$code = <<<PHP
if (\$condition)
{
if (\$other_condition)
{
do_something();
}
else
{
do_something_else();
}
}
PHP;

 

I am going to be posting text from a form and it is not PHP only but other languages and text as well.  So would:

 

$code = $_POST['code']

 

work with this function?

 

Thanks a lot! :D

Link to comment
Share on other sites

Yes, you can use whatever $code you want. But know that if it uses a different formatting and indentation scheme then you may get unusual results.

You do plan to try to understand what I wrote, right? At least how it works, if not the syntax to get it to do that.

Link to comment
Share on other sites

There is something weird though.  I entered your function into the post and it indented it, but for some reason it breaks its function and doesn't work when indented:

 

function indent($code) {
// first find all the sets of code blocks
$formatted = preg_replace_callback('/\{	(([^{}]*|(?R))*)\}/', function($matches) {
	// now we're replacing them
	// $matches[0] is the entire code block unformatted
	// $matches[1] is just the code inside
	$innercode = $matches[1];
	// apply indentation
	$innercode = preg_replace('/^[ \t]*\S/m', "\t\$0", $innercode);
	// then apply indentation to any code blocks inside this one
	$innercode = indent($innercode);
	// return. don't forget to add the {}s back
	return "{" . $innercode . "}";
}, $code);
return $formatted;
}

 

I also just noticed a problem that I am not sure can be resolved.  Some variables that are between quotations like

 

echo "Hello {$username}";

 

are converted into:

 

echo "Hello {    $username}";

 

If I had to guess on how to fix it, I would make it only indent after it detects an end paranthesis before the first curly bracket?  Like

 

if () {

}

 

it will see the

 

) {

 

or

 

) (next empty line)

{

 

as the trigger?

 

 

Link to comment
Share on other sites

Sorry, I had to make another post as I can no longer edit the one above.  I promise this will be the last time I bother you :)  Yes I see it tabbed after the first bracket in the function which is why it broke.  Can you make it only tab if the first curly bracket has an end parenthesis before it?  Also, it seems to tab even if there is already a tab within the parenthesis.  Thank you so much for your time :)

Link to comment
Share on other sites

You don't need brackets to echo variables in strings, mate:

 

echo "Hello {$username}"; can be rewritten as:

 

echo "Hello $username";

 

Yes I understand that thanks.  I am using this function to clean up code of old scripts that do use brackets within quotes.  I just need the function requinix created to only tab when the bracket comes after an end parenthesis and then it will be complete. 

Link to comment
Share on other sites

There is something weird though.  I entered your function into the post and it indented it, but for some reason it breaks its function and doesn't work when indented:

What?

 

I also just noticed a problem that I am not sure can be resolved.  Some variables that are between quotations like

 

echo "Hello {$username}";

 

are converted into:

 

echo "Hello {    $username}";

You're starting to get into territory that regular expressions can still handle but only with great difficulty and complication.

Try

'/^\s*\{(([^"\'{}]*|"([^\\\\"]+|\\\\.)*"|\'([^\\\\\']+|\\\\.)*\'|(?R))*)\}/m'

Link to comment
Share on other sites

Hello requinix, wow, that is some complex stuff :o  It worked when I entered the function as a test in the field and made it work.  However I tried pasting a whole file's worth of code like I did before and it resulted in a blank result.  Your regex worked fine before, is it possible it can just be slightly edited to only work after detecting an end parenthesis ) or perhaps only outside of quotation marks or some other workaround?  Thanks so much :)

Link to comment
Share on other sites

Replace the ^ with (^|\)\s*).

 

What code (to have indented) are you trying that isn't working?

 

Hello, I wasn't sure if you meant replace all of the ^ or just the first one, so I tried both:

 

'/(^|\)\s*)\s*\{(([(^|\)\s*)"\'{}]*|"([(^|\)\s*)\\\\"]+|\\\\.)*"|\'([(^|\)\s*)\\\\\']+|\\\\.)*\'|(?R))*)\}/m'

 

No indention, and the second time I only replaced the first ^

 

'/(^|\)\s*)\s*\{(([^"\'{}]*|"([^\\\\"]+|\\\\.)*"|\'([^\\\\\']+|\\\\.)*\'|(?R))*)\}/m'

 

It had a blank output.  Would it be easier if I pm'ed you the whole code and the file I am trying to edit or would you rather we continue posting in this topic?  Thanks :)

 

 

Link to comment
Share on other sites

You're taking the wrong approach to this.

 

You have to design a parser that is completely aware of the syntax. You then have to make sure there are no syntax errors that may break the script. You then have to split the code into it's individual parts without excess white space, and put it all back together, implementing the white spacing you want.

 

It's very, very complex and I suggest using an IDE with this functionality built in to achieve this.

 

Try writing a RegEx that will parse this as a string declaration.

echo "this"  . 'isn\'t very '.$easy." to do";

Link to comment
Share on other sites

xyph is right: the larger problem is knowing what can be indented and what cannot be, which requires a knowledge of the language and its grammar. The issue now is that apostrophes and {}s in comments are not ignored - the regex doesn't know that those are insignificant. For that matter, it would want to indent

// todo: look for any {s in the code are are not inside comments or strings,
// start a new indentation layer, and end the layer when the matching } appears

Currently you can stop that with the \)\s* requirement, but the [^'"{}] is the main problem. That needs to be broken apart and that is very difficult. Impossible if you want it language-agnostic.

 

In other words you've hit a dead end. From here you have to make something to indent specific languages (or at least languages with similar enough grammars, such as C/C++ and PHP).

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.