convert DIV to SPAN using str_replace - php

I have some data that is provided to me as $data, an example of some of the data is...
<div class="widget_output">
<div id="test1">
Some Content
</div>
<ul>
<li>
<p>
<div>768hh</div>
<div>2308d</div>
<div>237ds</div>
<div>23ljk</div>
</p>
</li>
<div id="temp3">
Some more content
</div>
<li>
<p>
<div>lkgh322</div>
<div>32khhg</div>
<div>987dhgk</div>
<div>23lkjh</div>
</p>
</li>
</div>
I am attempting to change the non valid HTML DIVs inside the paragraphs so i end up with this instead...
<div class="widget_output">
<div id="test1">
Some Content
</div>
<ul>
<li>
<p>
<span>768hh</span>
<span>2308d</span>
<span>237ds</span>
<span>23ljk</span>
</p>
</li>
<div id="temp3">
Some more content
</div>
<li>
<p>
<span>lkgh322</span>
<span>32khhg</span>
<span>987dhgk</span>
<span>23lkjh</span>
</p>
</li>
</div>
I am trying to do this using str_replace with something like...
$data = str_replace('<div>', '<span>', $data);
$data = str_replace('</div>', '</span', $data);
Is there a way I can combine these two statements and also make it so that they only affect the 'This is a random item' and not the other occurences?

$data = str_replace(array('<div>', '</div>'), array('<span>', '</span>'), $data);
As long as you didn't give any other details and only asked:
Is there a way I can combine these two statements and also make it so that they only affect the 'This is a random item' and not the other occurences?
Here you go:
$data = str_replace('<div>This is a random item</div>', '<span>This is a random item</span>', $data);

You'll need to use a regular expression to do what you are looking to do, or to actually parse the string as XML and modify it that way. The XML parsing is almost surely the "safest," since as long as the string is valid XML, it will work in a predictable way. Regexes can at times fall prey to strings not being in exactly the expected format, but if your input is predictable enough, they can be ok. To do what you want with regular expressions, you'd so something like
$parsed_string = preg_replace("~<div>(?=This is a random item)(.*?)</div>~", "<span>$1</span>, $input_string);
What's happening here is the regex is looking for a <div> tag which is followed by (using a lookahead assertion) This is a random item. It then captures any text between that tag and the next </div> tag. Finally, it replaces the match with <span>, followed by the captured text from inside the div tags, followed by </span>. This will work fine on the example you posted, but will have problems if, for example, the <div> tag has a class attribute. If you are expecting things like that, either a more complex regular expression would be needed, or full XML parsing might be the best way to go.

I'm a little surprised by the other answers, I thought someone would post a good one, but that hasn't happened. str_replace is not powerful enough in this case, and regular expressions are hit-and-miss, you need to write a parser.
You don't have to write a full HTML-parser, you can cheat a bit.
$in = '<div class="widget_output">
(..)
</div>';
$lines = explode("\n", $in);
$in_paragraph = false;
foreach ($lines as $nr => $line) {
if (strstr($line, "<p>")) {
$in_paragraph = true;
} else if (strstr($line, "</p>")) {
$in_paragraph = false;
} else {
if ($in_paragraph) {
$lines[$nr] = str_replace(array('<div>', '</div>'), array('<span>', '</span>'), $line);
}
}
}
echo implode("\n", $lines);
The critical part here is detecting whether you're in a paragraph or not. And only when you're in a paragraph, do the string replacement.
Note: I'm splitting on newlines (\n) which is not perfect, but works in this case. You might want to improve this part.

Related

PHP Strip all content around text

I have text that looks like this or a billion variant of this, for example:
<div>content goes here... </div><div style="some style..."><span style="some styles..."><strong>[END_CONTACT]</strong></span></div><div>content goes here... </div>
<div>content goes here... </div><div style="other style..."><span style="other styles..."><strong>[END_CONTACT]</strong></span></div><div>content goes here... </div>
<div>content goes here... </div><div style="random stuff..."><span style="random stuff..."><strong>[END_CONTACT]</strong></span></div><div>content goes here... </div>
and a billion variations of this...
I want to be able to remove any variation of the text surrounding [END_CONTACT] so that all I am left with this is this:
<div>content goes here... </div><div>[END_CONTACT]</div><div>content goes here... </div>
How do I strip the content between the opening div tag and [END_CONTACT] and the content between [END_CONTACT] and the ending div tag?
Thanks
Use regular expressions! The following example using preg_replace will work as long as your content doesn't contain angle brackets, which you should not put in HTML.
$result = preg_replace('#<div\b[^>]*><span\b[^>]*><strong\b[^>]*>([^<]*)</strong></span></div>#i', '<div>$1</div>', $html);
How do I strip the content between the opening div tag and [END_CONTACT] and the content between [END_CONTACT] and ending div tag?
If the terms [END_CONTACT] and the <div> tag are always present, you can use PCRE REGEX in preg_replace():
$string = preg_replace('/<div[^>]*>.*\[END_CONTACT\].*<\/div>/i','<div>[END_CONTACT]</div>',$string);
Example:
$data = [];
$data[] = 'some text <div style="some style..."><span style="some styles..."><strong>[END_CONTACT]</strong></span></div>';
$data[] = 'somrthing else etc.<div style="other style..."><span style="other styles..."><strong>[END_CONTACT]</strong></span></div>';
$data[] = '<div style="random stuff..."><span style="random stuff..."><strong>[END_CONTACT]</strong></span></div>';
$data[] = 'and a billion variations of this...';
foreach ($data as $row){
$string = preg_replace('/<div[^>]*>.*\[END_CONTACT\].*<\/div>/i','<div>[END_CONTACT]</div>',$row);
print $string."<BR>";
}
Output:
<div>[END_CONTACT]</div>
<div>[END_CONTACT]</div>
<div>[END_CONTACT]</div>
and a billion variations of this...
UPDATE:
Sorry, wasn't clear about that in my original post. Is there any way to keep text or code outside of the string in question but still do the operation as you've suggested?
Try this Regex in the above PHP code:
(?!<div).(<div[^>]*>.*\[END_CONTACT\][^\div]*<\/div>)
Example:
content content content... <div style="random stuff..."><span style="random stuff..."><strong>[END_CONTACT]</strong></span></div> content content content
Output:
content content content... <div>[END_CONTACT]</div> content content content
NOTE:
It must be stated that you should use a DOM parser to work with HTML elements in complex compositions rather than Regex.
I have tested my answer and it does what is desired. And as stated above, what you should be using to deal with multilayered complex HTML is a proper PHP DOM Parser.

How to format plaintext in PHP Simple HTML DOM Parser?

I'm trying to extract the content of a webpage in plain text - without the html tags. Here's some sample code:
$dom = \Sunra\PhpSimple\HtmlDomParser::file_get_html($url);
$result['body'] = $dom->find('body', 0)->plaintext;
The problem is that what I get in $result['body'] is very messy. The HTML was removed, sure, but sentences often merge into others since there are no spaces or periods to delimit where the text from one HTML tag ended, and text from the following tag begins.
An example:
<body>
<div class="H2">Header</div>
<div class="P">this is a paragraph</div>
<div class="P">this is another paragraph</div>
</body>
Results in:
"Headerthis is a paragraphthis is another paragraph"
Desired result:
"Header. this is a paragraph. this is another paragraph"
Is there any way to format the result from plaintext or perhaps apply extra manipulation on the innertext before using plaintext to achieve clear delimiters for sentences?
EDIT:
I'm thinking of doing something like this:
foreach($dom->find('div') as $element) {
$text = $element->plaintext;
$result['body'] .= $text.'. ';
}
but there's a problem when the divs are nested, since it would add the content of the parent, which includes text from all children, and then add the content of the children, effectively duplicating the text. This can be fixed simply by checking if there is a </div> inside the $text though.
Perhaps I should try callbacks.
Possibly something like this? Tested.
<?php
require_once 'vendor/autoload.php';
$dom = \Sunra\PhpSimple\HtmlDomParser::file_get_html("index.html");
$result['body'] = implode('. ', array_map(function($element) {
return $element->plaintext;
}, $dom->find('div')));
echo $result['body'];
<body>
<div class="H2">Header</div>
<div class="P">this is a paragraph</div>
<div class="P">this is another paragraph</div>
</body>
Try this code:
$result = array();
foreach($html->find('div') as $e){
$result[] = $e->plaintext;
}

How to extract HTML element from a source file

I need to replace a HTML section identified by a tag id in a source code, which is combination of HTML and PHP using PHP. In case it's pure HTML, DOM parser could be used; in case there is no DIV in DIV, I can imagine how to use preg_match. This is what I am trying to do - I have a code (loaded into a string) like:
<div>
<img >
</div>
<? include(); ?>
<div id="mydiv">
<div>
<div>
<img >
</div>
</div>
</div>
and my task is to replace content of "mydiv" DIV with a new one e.g.
<div id="newdiv>
some text
</div>
so the string will look like this after the change:
<div>
<img >
</div>
<? include(); ?>
<div id="mydiv">
<div id="newdiv>
some text
</div>
</div>
I have already tried:
1) parsing the code using DOMdocument's loadHTML => it produces a lot of errors in case PHP code is included.
2) I played around a bit with regexes like preg_match_all('/<div id="myid"([^<]*)<\/div>/', $src, $matches), which fails in case more child divs are included.
The best approach I have found so far is:
1) find id="mydiv" string
2) search for '<' and '>' chars and count them like '<'=1 and '>'=-1 (not exactly, but it gives the idea)
3) once I get sum == 0 I should be on position of the closing tag, so I know, which portion string I should exchange
This is quite "heavy" solution, which can stop working in some cases, where the code is different (e.g. onpage PHP code contains the chars as well instead of just simple "include"). So I am looking so some better solution.
You could try something like this:
$file = 'filename.php';
$content = file_get_contents($file);
$array_one = explode( '<div id="mydiv">' , $content );
$my_div_content = explode("</div>" , $array_one[1] )[0];
Or use preg_match like you said:
preg_match('/<div id="mydiv"(.*?)<\/div>/s', $content, $matches)
Yes there is. First you need to use a function that will get the content of the file. Lets call the file homepage.php:
$homepageString = file_get_contents('homepage.php');
Now you have a string with all the content. The next thing you would do is use the preg_replace() function to take out the part of code that you want to take out:
$newHomepageString = preg_replace('/id="mydiv"/',"", $homepageString);
Now you overwrite the existing homepage.php file with the new source code:
file_put_contents("homepage.php", $newHomepageString);
Let me know if it worked for you! :)

filter php variable for specific bbcode string - wrap matches inside of divs?

hey guys,
my php variable $content holds html!
i want to filter this $content for
[q=SomeQuestoin] and [a=SomeAnswer]
and wrap each match inside of a div.question and div.answer.
So whenever this [q=Some Question][a=Some Answer] structure is found in $content i want to put out this.
<div class="qanda">
<div class="question">
Some Question
</div>
<div class="answer">
Some Answer
</div>
</div>
Is that possible? Important is that the Qustion Text or the Answer Text could hold html tags as well. like <p> or <b> etc.
update:
$q_regex = '/\[q=([^"]+?)]/is';
$q_output = '<div class="qanda"><div class="queston">$1</div>';
$content = preg_replace($q_regex, $q_output, $content);
$a_regex = '/\[a=([^"]+?)]/is';
$a_output = '<div class="answer">$1</div></div>';
$content = preg_replace($a_regex, $a_output, $content);
http://www.spotlesswebdesign.com/blog.php?id=12
tutorial on using regex to do bbcode parsing. people would recommend using a bbcode parser module however. should be safe to regex since you are not using nesting and whatnot.
EDIT
possible but tricky. could be error prone. something like this maybe:
$result = preg_replace('/\[q=(.+?)].+?\[a=(.+?)]/is', '<div class="qanda"><div class="question">$1</div><div class="answer">$2</div></div>', $subject);

Regular expression for DIV elements

Say I had this piece of HTML for example:
<div id="gallery2" class="galleryElement">
<h2>My Photos</h2>
<div class = "imageElement">
<h3>#Embassy - VIP </h3>
<p><b>Image URL:</b>
http://photos-p.friendster.com/photos/78/86/77426887/1_119466535.jpg</p>
<img src = "http://photos-p.friendster.com/photos/78/86/77426887/1_119466535.jpg" class = "full"/>
<img src = "http://photos-p.friendster.com/photos/78/86/77426887/1_887303260m.jpg" class = "thumbnail"/>
</div>
<div class = "imageElement">
<h3>#Embassy - VIP </h3>
<p><b>Image URL:</b>
http://photos-p.friendster.com/photos/78/86/77426887/1_119466535.jpg</p>
<img src = "http://photos-p.friendster.com/photos/78/86/774534426887/1_119466535.jpg" class = "full"/>
<img src = "http://photos-p.friendster.com/photos/78/86/774534426887/1_887303260m.jpg" class = "thumbnail"/>
</div>
</div>
I need to build the proper regular expression to parse each div class'ed as imageElement and store the contents (as text) in an array starting from the opening <div class = "imageElement"> till its ending div pair </div>. Also, there really are spaces on class = "imageElement". So far I have the expression:
\<div class = "imageElement">[\s\S\d\D]*</div>
but it only gets the whole set of elements. Thanks in advance.
This is a pretty common question here ("How do I parse this XML/HTML with a regular expression?") and I'll give you the same answer: don't.
Regular expressions are notoriously bad at this kind of thing. HTML/XML is not "regular" in the regex sense.
PHP comes with at least 3 XML parsers (SimpleXML, DOMDocument and XMLReader spring to mind) that will do this reliably. Use one of those.
Take a look at Parse HTML With PHP And DOM as an example.
sounds like the trouble you're having is that the * is greedy, ie it matches as much as possible, where you want it to match a little as possible.
If the data inside your divs does not contain "</div>" then you can keep the parsing pretty simple. If it can contain arbitrary HTML data (specifically nested divs), you'll need to parse it more.
If it stays basic, you could do the whole thing without regex. It's a little hackish, but as long as your data says simple, and expected, it should work really fast:
$chunks = explode($body, '<div class = "imageElement">');
array_shift($chunks);
$matches = array();
foreach($chunks as $chunk) {
$pos = strpos('</div>', $chunk);
if($pos) {
$matches[] = substr($chunk, 0, $pos);
{
}
If you need something more flexible, use a real html parser.

Categories