add own text inside nested braces
<p>I have this source of text which contains HTML tags and PHP code at the same time:
<div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
<div class="snippet-code">
<pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;html&gt;
&lt;head&gt;
&lt;title&gt;&lt;?php echo "title here"; ?&gt;&lt;/title&gt;
&lt;head&gt;
	&lt;body&gt;
		&lt;h1 &lt;?php echo "class='big'" ?&gt;&gt;foo&lt;/h1&gt;
	&lt;/body&gt;
&lt;/html&gt;</code></pre>
</div>
</div>
</p>

<p>and I need place my own text (for example: MY_TEXT) after opened  tag and get this result:</p>

<p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
<div class="snippet-code">
<pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;html&gt;
&lt;head&gt;
&lt;title&gt;&lt;?php echo "title here"; ?&gt;&lt;/title&gt;
&lt;head&gt;
	&lt;body&gt;
		&lt;h1 &lt;?php echo "class='big'" ?&gt;&gt;MY_TEXTfoo&lt;/h1&gt;
	&lt;/body&gt;
&lt;/html&gt;</code></pre>
</div>
</div>
</p>

<p>thus I need consider nested braces</p>

<p>if I will use regex it will creates problems (I need consider any level of nested braces). I need another strategy.</p>

<p>now my idea try to use pyparsing, but I can't get it now, too complicated for my current level</p>

<p>could anybody make solution please?</p>

<p>Pyparsing has a helper method called <code>nestedExpr</code> that makes it easy to match strings of nested open/close delimiters. Since you have nested PHP tags within your <code>&lt;h1&gt;</code> tag, then I would use a <code>nestedExpr</code> like:</p>

<pre><code>nested_angle_braces = nestedExpr('&lt;', '&gt;')
</code></pre>

<p>However, this will match <em>every</em> tag in your input HTML source:</p>

<pre><code>for match in nested_angle_braces.searchString(html):
    print match
</code></pre>

<p>gives:</p>

<pre><code>[['html']]
[['head']]
[['title']]
[['?php', 'echo', '"title here"', ';', '?']]
[['/title']]
[['head']]
[['body']]
[['h1', ['?php', 'echo', '"class=\'big\'"', '?']]]
[['/h1']]
[['/body']]
[['/html']]
</code></pre>

<p>You want to match <em>only</em> those tags whose opening text is 'h1'. We can add a condition to an expression in pyparsing using <code>addCondition</code>:</p>

<pre><code>nested_angle_braces_with_h1 = nested_angle_braces().addCondition(
                                            lambda tokens: tokens[0][0].lower() == 'h1')
</code></pre>

<p>Now we will match only the desired tag. Just a few more steps...</p>

<p>First of all, <code>nestedExpr</code> gives back nested lists of matched items. We want the original text that was matched. Pyparsing includes another helper for that, unimaginatively named <code>originalTextFor</code> - we combine this with the previous definition to get:</p>

<pre><code>nested_angle_braces_with_h1 = originalTextFor(
    nested_angle_braces().addCondition(lambda tokens: tokens[0][0].lower() == 'h1')
    )
</code></pre>

<p>Lastly, we have to add one more parse-time callback action, to append "MY_TEXT" to the tag:</p>

<pre><code>nested_angle_braces_with_h1.addParseAction(lambda tokens: tokens[0] + 'MY_TEXT')
</code></pre>

<p>Now that we are able to match the desired <code>&lt;h1&gt;</code> tag, we can use <code>transformString</code> method of the expression to do the search-and-replace work for us:</p>

<pre><code>print(nested_angle_braces_with_h1.transformString(html))
</code></pre>

<p>With your original sample saved as a variable named <code>html</code>, we get:</p>

<pre><code>&lt;html&gt;
&lt;head&gt;
&lt;title&gt;&lt;?php echo "title here"; ?&gt;&lt;/title&gt;
&lt;head&gt;
        &lt;body&gt;
                &lt;h1 &lt;?php echo "class='big'" ?&gt;&gt;MY_TEXTfoo&lt;/h1&gt;
        &lt;/body&gt;
&lt;/html&gt;
</code></pre>

<p>Note: this will add "MY_TEXT" after <em>every</em> <code>&lt;h1&gt;</code> tag. If you want this to be applied <em>only</em> after <code>&lt;h1&gt;</code> tags containing PHP, then write the appropriate condition and add it to <code>nested_angle_braces_with_h1</code>.</p>

python pyparsing python-textprocessing