I have a private website where I share videos (and some other stuff).
What I have achieved is that with preg_match_all() it automatically finds the link and it paste the video with the HTML code to my website.
Here an example:
<?php
$matchwith = "http://videosite.com/id1 http://videosite.com/id2 http://videosite.com/id3";
preg_match_all('/videosite\.com\/(\w+)/i', $matchwith, $matches);
foreach($matches[1] as $value)
{
print 'Hyperlink';
}
?>
This works. I know this could may could be done easier, but it has to be this way.
But I do not know how this with a two part movie. Here an example:
$matchWith = "http://videosite.com/id1_movie1 http://videosite.com/id2_movie1"
"http://videosite.com/id3_movie2 http://videosite.com/id4_movie2";
Everything after http://videosite.com/(...) is unique.
What I want is if you write Part 1 and Part 2 (or whatever) before the link, that it automatically detects it as Part 1 and Part 2 of this video.
$matchwith could contain different movies.
So I believe this is what you need:
<?php
$matchWith = "Movie 1 http://videosite.com/id1" . PHP_EOL .
"Movie 1 http://videosite.com/id2" . PHP_EOL .
"Movie 2 http://videosite.com/id3";
$arrLinks = array();
preg_match_all('%(.*)\shttp://videosite\.com/(\w+)\r{0,1}%', $matchWith, $result, PREG_SET_ORDER);
for ($matchi = 0; $matchi < count($result); $matchi++) {
$arrLinks[$result[$matchi][1]][] = $result[$matchi][2];
}
foreach ($arrLinks as $movieName => $arrMovieIds) {
print '<div>' . $movieName . '</div>';
foreach ($arrMovieIds as $movieId) {
print 'Hyperlink<br/>';
}
}
?>
$matchwith = "Part 1 http://videosite.com/id1-1 Part2 http://videosite.com/id1-2";
preg_match_all('/videosite\.com\/(\w+-\d+)/i', $matchwith, $matches);
foreach($matches[1] as $value)
{
print 'Hyperlink';
}
Related
So I have the following function:
function findMatches($pathToDirectory, $keyword){
$results = array();
$htmlString = "";
$fileList = glob($pathToDirectory);
natsort($fileList);
foreach ($fileList as $search) {
$contents = file_get_contents($search);
$episodeTitle = fgets(fopen($search, 'r'));
$episodeTitle = "<p class='episode_title'>$episodeTitle</p>";
$sentences = preg_split('/(?<=[.])\s+(?=[a-z])/i', $contents);
foreach ($sentences as $sentence) {
if (strpos($sentence, $keyword)) {
if (!in_array($episodeTitle, $results)) {
array_push($results, $episodeTitle);
}
array_push($results, $sentence);
}
}
}
foreach ($results as $result){
$highlightedKeyword = '<span class="keyword_highlight">' . $keyword . '</span>';
$newResult = str_replace($keyword, $highlightedKeyword, $result);
$htmlString .= '<p class="search_result">' . $newResult . '</p>';
}
$totalResults = 'Total Results: <span class=\'number_result\'>' . count($results) . '</span>';
return $htmlString = $totalResults . $htmlString;
}
It opens every text file in a directory ($filelist), takes its contents, splits them up into sentences ($sentences), and then saves the sentences that contain a user defined keyword into an array ($results). Then, it iterates through $results to wrap the keyword in HTML (so that the word appears highlighted within the sentence to the user), and and finally it wraps each sentence in HTML and sends them for presentation to the user.
However, currently the function is case sensitive. What's a good way to make it case insensitive? I tried using stripos() instead of strpos() in the foreach ($sentences as $sentence) loop, and that made the search itself case insensitive (like I want), but the problem is I couldn't figure out how to highlight both upper and lowercase versions of the word correctly if I wrote the function this way.
Also please let me know if you need clarification on any of this, I'm not sure I explained it too well
You need to use stripos() and also str_ireplace() when you're doing your highlighting.
I have a string variable which contains some text (shown below). The text has line breaks in it as shown. I would like to search the text for a given string, and return the number of matches per line number. For instance, searching for "keyword" would return 1 match on line 3 and 2 matches on line 5.
I have tried using strstr(). It does a good job finding the first match, and giving me the remaining text, so I can do it again and again until there are no matches. Problem is I do not know how to determine which line number the match occurred on.
Hello,
This is some text.
And a keyword.
Some more text.
Another keyword! And another keyword.
Goodby.
Why not split the text on line-feeds and loop, use the index + 1 as a line number:
$txtParts = explode("\n",$txt);
for ($i=0, $length = count($txtParts);$i<$length;$i++)
{
$tmp = strstr($txtParts[$i],'keyword');
if ($tmp)
{
echo 'Line '.($i +1).': '.$tmp;
}
}
Tested, and working. Just a quick tip, since you're looking for matches in a text (sentences, upper- and lower-case etc...) perhaps stristr (case-insensitive) would be better?An example with foreach and stristr:
$txtParts = explode("\n",$txt);
foreach ($txtParts as $number => $line)
{
$tmp = stristr($line,'keyword');
if ($tmp)
{
echo 'Line '.($number + 1).': '.$tmp;
}
}
With this code you can have all data in one array (Linenumber and position numbers)
<?php
$string = "Hello,
This is some text.
And a keyword.
Some more text.
Another keyword! And another keyword.
Goodby.";
$expl = explode("\n", $string);
$linenumber = 1; // first linenumber
$allpos = array();
foreach ($expl as $str) {
$i = 0;
$toFind = "keyword";
$start = 0;
while($pos = strpos($str, $toFind, $start)) {
//echo $toFind. " " . $pos;
$start = $pos+1;
$allpos[$linenumber][$i] = $pos;
$i++;
}
$linenumber++; // linenumber goes one up
}
foreach ($allpos as $linenumber => $position) {
echo "Linenumber: " . $linenumber . "<br/>";
foreach ($position as $pos) {
echo "On position: " .$pos . "<br/>";
}
echo "<br/>";
}
Angelo's answer definitely provides more functionality and is probably the best answer, but the following is simple and seems to work. I will continue to play with all solutions.
function findMatches($text,$phrase)
{
$list=array();
$lines=explode("\n", $text);
foreach($lines AS $line_number=>$line)
{
str_replace($phrase,$phrase,$line,$count);
if($count)
{
$list[]='Found '.$count.' match(s) on line '.($line_number+1);
}
}
return $list;
}
I am looking to convert a string with a special HTML tag and parse it accordingly. Below I will show what the original string is followed by what I want the parsed string to be. If someone can direct me towards a proper coding method to make this possible that would be fantastic.
Original String:
$string = '<string 1="Jacob" 2="ice cream">{1} likes to have a lot of {2}.</string>';
Parsed String:
$parsed_string = 'Jacob likes to have a lot of ice cream.';]
EDIT:
I forgot to add that the $string variable may having multiple strings with multiple options, for example the $string variable could be the following:
$string = '<string 1="hot dog">I like to have {1}</string> on <string 1="beach" 2="sun">the {1} with the blazing hot {2} staring down at me.';
I need a solution that can parse the code example above.
EDIT 2:
Here is a sample code I developed that is incomplete and has a few bugs. If there is more than one option e.x. 1='blah' 2='blahblah' it will not parse the second option.
$string = '<phrase 1="Jacob" 2="cool">{1} is {2}</phrase> when <phrase 1="John" 2="Chris">{1} and {2} are around.</phrase>';
preg_match_all('/<phrase ([0-9])="(.*?)">(.*?)<\/phrase>/', $string, $matches);
print $matches[1][0] . '<br />';
print $matches[2][0] . '<br />';
print $matches[3][0] . '<br />';
print '<hr />';
$string = $matches[3][0];
print str_replace('{' . $matches[1][0] . '}', $matches[2][0], $output);
print '<hr />';
print '<pre>';
print_r($matches);
print '</pre>';
As $string is no valid XML (e.g. containing numbers as attribute names), you may try:
$string = '<string 1="Jacob" 2="ice cream">{1} likes to have a lot of {2}.</string>';
$parsed_string = strip_tags($string);
for ($i = 1; $i <= 2; $i++) {
if (preg_match('/' . $i . '="([^"]+)"/', $string, $match))
$parsed_string = str_replace('{' . $i .'}', $match[1], $parsed_string);
}
echo $parsed_string;
UPDATE
Your EDIT switched from having one <string> tag to having multiple <string> tags in the variable now. This one should work for multiples:
$string2 = '<string 1="hot dog">I like to have {1}</string> on <string 1="beach" 2="sun">the {1} with the blazing hot {2} staring down at me.</string>';
$parsed_string2 = '';
$a = explode('</string>', $string2);
foreach ($a as $s) {
$parsed_elm = strip_tags($s);
for ($i = 1; $i <= 2; $i++) {
if (preg_match('/' . $i . '="([^"]+)"/', $s, $match))
$parsed_elm = str_replace('{' . $i .'}', $match[1], $parsed_elm);
}
$parsed_string2 .= $parsed_elm;
}
echo $parsed_string2;
<?php
$rows = array();
$xml = "
<string 1="Jacob" 2="ice cream">{1} likes to have a lot of {2}.</string>
<string 1="John" 2="cream">{1} likes to have a lot of {2}.</string>
"
$parser = xml_parser_create();
xml_parse_into_struct($parser, trim($xml), $xml_values);
foreach ($xml_values as $row){
$finalRow = $row['values'];
foreach ($row['attributes'] as $att => $attval){
$finalRow = str_replace ($finalRow, "{".$att."}", $attval);
}
$rows[] = $finalRow;
}
?>
Here's a version that doesn't use regex, this seemed more straight forward. I don't know how the xml parser would cope with attributes that start with a number though.
Im working on a commenting web application and i want to parse user mentions (#user) as links. Here is what I have so far:
$text = "#user is not #user1 but #user3 is #user4";
$pattern = "/\#(\w+)/";
preg_match_all($pattern,$text,$matches);
if($matches){
$sql = "SELECT *
FROM users
WHERE username IN ('" .implode("','",$matches[1]). "')
ORDER BY LENGTH(username) DESC";
$users = $this->getQuery($sql);
foreach($users as $i=>$u){
$text = str_replace("#{$u['username']}",
"<a href='#' class='ct-userLink' rel='{$u['user_id']}'>#{$u['username']}</a> ", $text);
}
$echo $text;
}
The problem is that user links are being overlapped:
<a rel="11327" class="ct-userLink" href="#">
<a rel="21327" class="ct-userLink" href="#">#user</a>1
</a>
How can I avoid links overlapping?
Answer Update
Thanks to the answer picked, this is how my new foreach loop looks like:
foreach($users as $i=>$u){
$text = preg_replace("/#".$u['username']."\b/",
"<a href='#' title='{$u['user_id']}'>#{$u['username']}</a> ", $text);
}
Problem seems to be that some usernames can encompass other usernames. So you replace user1 properly with <a>user1</a>. Then, user matches and replaces with <a><a>user</a>1</a>. My suggestion is to change your string replace to a regex with a word boundary, \b, that is required after the username.
The Twitter widget has JavaScript code to do this. I ported it to PHP in my WordPress plugin. Here's the relevant part:
function format_tweet($tweet) {
// add #reply links
$tweet_text = preg_replace("/\B[#@]([a-zA-Z0-9_]{1,20})/",
"#<a class='atreply' href='http://twitter.com/$1'>$1</a>",
$tweet);
// make other links clickable
$matches = array();
$link_info = preg_match_all("/\b(((https*\:\/\/)|www\.)[^\"\']+?)(([!?,.\)]+)?(\s|$))/",
$tweet_text, $matches, PREG_SET_ORDER);
if ($link_info) {
foreach ($matches as $match) {
$http = preg_match("/w/", $match[2]) ? 'http://' : '';
$tweet_text = str_replace($match[0],
"<a href='" . $http . $match[1] . "'>" . $match[1] . "</a>" . $match[4],
$tweet_text);
}
}
return $tweet_text;
}
instead of parsing for '#user' parse for '#user ' (with space in the end) or ' #user ' to even avoid wrong parsing of email addresses (eg: mailaddress#user.com) maybe ' #user: ' should also be allowed. this will only work, if usernames have no whitespaces...
You can go for a custom str replace function which stops at first replace.. Something like ...
function str_replace_once($needle , $replace , $haystack){
$pos = strpos($haystack, $needle);
if ($pos === false) {
// Nothing found
return $haystack;
}
return substr_replace($haystack, $replace, $pos, strlen($needle));
}
And use it like:
foreach($users as $i=>$u){
$text = str_replace_once("#{$u['username']}",
"<a href='#' class='ct-userLink' rel='{$u['user_id']}'>#{$u['username']}</a> ", $text);
}
You shouldn’t replace one certain user mention at a time but all at once. You could use preg_split to do that:
// split text at mention while retaining user name
$parts = preg_split("/#(\w+)/", $text, -1, PREG_SPLIT_DELIM_CAPTURE);
$n = count($parts);
// $n is always an odd number; 1 means no match found
if ($n > 1) {
// collect user names
$users = array();
for ($i=1; $i<$n; $i+=2) {
$users[$parts[$i]] = '';
}
// get corresponding user information
$sql = "SELECT *
FROM users
WHERE username IN ('" .implode("','", array_keys($users)). "')";
$users = array();
foreach ($this->getQuery($sql) as $user) {
$users[$user['username']] = $user;
}
// replace mentions
for ($i=1; $i<$n; $i+=2) {
$u = $users[$parts[$i]];
$parts[$i] = "<a href='#' class='ct-userLink' rel='{$u['user_id']}'>#{$u['username']}</a>";
}
// put everything back together
$text = implode('', $parts);
}
I like dnl solution of parsing ' #user', but maybe is not suitable for you.
Anyway, did you try to use strip_tags function to remove the anchor tags? That way you have the string without the links, and you can parse it building the links again.
strip_tags
I have an array, which I am using the following code:
foreach ($taglist as $tag=>$size){
echo link_to(
$tag,
"#search-tag?tag=" . strtolower($tag),
array(
"class" => 'tag' . $size,
"title" => "View all articles tagged '" . $tag . "'"
)
);
}
Now, this simply prints a hyperlink
What I'm looking to do, is to add the pipe char ( | ) after every link, apart from the last one.
Could I do this in a loop?
Thanks
$k = 0;
foreach($taglist as $tag=>$size)
{
$k++;
echo link_to($tage, ...);
if ($k != sizeof($taglist)) echo '|';
}
You can use a plain old boolean variable:
$first = true;
foreach($taglist as $tag=>$size){
if ($first) $first = false; else echo '|';
echo link_to($tage, ...);
}
Note that technically, this code outputs a bar before every element except the first, which has the exact same effect as outputting a bar after every element except the last.
Use a temporary array then join elements /
$links = array();
foreach($taglist as $tag=>$size){
$links[] = link_to($tag, ...);
}
echo implode('|', $links);
You can use a CachingIterator
$links = new CachingIterator(new ArrayIterator($tagList));
foreach($links as $tag => $size) {
echo link_to(/* bla */), $links->hasNext() ? '|' : '';
}
For more info on the CachingIterator see my answer at Peek ahead when iterating an array in PHP