"like" search and highlighting in PHP - php

I have list of brands and want to provide a search function with highlighting. For example, there are the following brands
Apple
Cewe Color
L'Oréal
Microsoft
McDonald's
Tom Tailor
The user then types lor in search form. I'm using the following snippet for searching
class search {
private function simplify($str) {
return str_replace(array('&',' ',',','.','?','|','\'','"'), '', iconv('UTF-8', 'ASCII//TRANSLIT', $str));
}
public function do_search($search) {
$search = self::simplify($search);
$found = array();
foreach (self::$_brands as $brand) {
if (mb_strstr(self::simplify($brand['name']), $search) !== false) $found[]= $brand;
}
return $found;
}
}
That gives me:
Cewe Color
L'Oréal
Tom Tailor
How would be a highlighting possible? Like:
Cewe Co<b>lor</b>
L'<b>Oré</b>al
Tom Tai<b>lor</b>
Btw: I know, that most things can be done with str_replace(), but that fit my needs not in all cases

$highlighted = str_replace($search, "<b>$search</b>", $brand);
would be the simplest method.

:)
Works with FedEx also ;)
$_brands = array
(
"Apple",
"Cewe Color",
"L'Oréal",
"Microsoft",
"McDonald's",
"Tom Tailor"
);
$q = 'lor';
$search = clean($q);
foreach($_brands as $key => $brand){
$brand = clean($brand);
$x = stripos($brand, $search);
if($x !== false){
$regexp = NULL;
$l = strlen($q);
for($i = 0; $i < $l; $i++){
$regexp .= mb_strtoupper($q[$i]).'.?';
}
$regexp = substr($regexp, 0, strlen($regexp) - 2);
$new = $_brands[$key];
$new = preg_replace('#('.$regexp.')#ui', '<b>$0</b>', $new);
echo $new."<br />";
}
}
function clean($string){
$string = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $string);
$string = preg_replace('#[^\w]#ui', '', $string);
return $string;
}

self::$_brands contains result from database (containing columns name, name_lower, name_translit, name_simplified)
class search {
private function translit($str) {
return iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', str_replace(array('ä', 'ü', 'ö', 'ß'), array('a', 'u', 'o', 's'), mb_strtolower($str)));
}
private function simplify($str) {
return preg_replace('/([^a-z0-9])/ui', '', self::translit($str));
}
public function do_search($simplified) {
$found = array();
foreach (self::$_brands as $brand) {
if (mb_strstr($brand['name_simplified'], $simplified) !== false) $found[]= $brand;
}
return $found;
}
private function actionDefault() {
$search = $_POST['search_fld'];
$simplified = self::simplify($search);
$result = self::do_search($simplified);
$brands = array();
foreach ($result as $brand) {
$hl_start = mb_strpos($brand['name_simplified'], $simplified);
$hl_len = mb_strlen($simplified);
$brand_len = mb_strlen($brand['name']);
$tmp = '';
$cnt_extra = 0;
$start_tag = false;
$end_tag = false;
for ($i = 0; $i < $brand_len; $i++) {
if (($i - $cnt_extra) < mb_strlen($brand['name_simplified']) && mb_substr($brand['name_translit'], $i, 1) != mb_substr($brand['name_simplified'], $i - $cnt_extra, 1)) $cnt_extra++;
if (($i - $cnt_extra) == $hl_start && !$start_tag) {
$tmp .= '<b>';
$start_tag = true;
}
$tmp .= mb_substr($brand['name'], $i, 1);
if (($i - $cnt_extra + 1) == ($hl_start + $hl_len) && !$end_tag) {
$tmp .= '</b>';
$end_tag = true;
}
}
if ($start_tag && !$end_tag) $tmp .= '</b>';
$brands[] = "" . $tmp . "";
}
echo implode(' | ', $brands);
}
}

Related

Naive Bayes in PHP

I’m trying to implement a Naive Bayes classifier in PHP, and I found this script.
I’m running the script on a standard LAMP stack (php-fpm), and I am getting a an error:
Fatal error: Call to undefined function 3184791920() in
/location/file.php on line 73
But I can't figure out what is causing this, since there is no 3184791920() function. I assume it has something to do with the hashing:
define("LL_NB_HASH_FUNCTION", "crc32");
Here is the full text of my implementation:
<?php
global $LL_NB_STOP_WORDS;
$LL_NB_STOP_WORDS = array("a", "about", "above", "...");
define("LL_NB_HASH_FUNCTION", "crc32");// crc32 is the fastest built in hash function.
// $xs is a bunch of "strings" and ys are their labels.
function ll_naivebayes($xs, $ys, $testStrings) {
$topicWords = array();
foreach($xs as $i=>$x) {
if(isset($topicWords[$ys[$i]]))
$topicWords[$ys[$i]] .= $x;
else
$topicWords[$ys[$i]] = $x;
}
$topicWords = _ll_computeWordCounts($topicWords); // get the number of each word, by topic.
$probWordsGivenTopic = array(); // probability of each word in a given topic.
$countTopics = array();
foreach($topicWords as $topicIndex=>$xWordCounts) {
$totalWordsTopic = array_sum($xWordCounts);
$countTopics[$topicIndex] = $total_wordsTopic;
foreach($xCount as $hash=>$count) {
$probWordsGivenTopic[$topicIndex][$hash] = ($count/$totalWordsTopic);
}
}
$probTopics = array(); // probability of a given topic (number of words / total words), i.e., relative frequency of topics in terms of words
foreach($countTopics as $i=>$topicCount) {
$probTopics[$i] = ($topicCount/$totalWords);
}
if(!is_array($testStrings))
$testStrings = array($testStrings);
// process the input testStrings array
$return = array();
foreach($testStrings as $i=>$string) {
$testStringWords = _ll_computeWordCount($string);
$topicsPosterior = array();
foreach($probTopics as $key=>$probTopic) {
$p = $probTopic;
foreach($testStringWords as $hash=>$count) {
if(isset($probWordsGivenTopic[$key][$hash]))
$p *= $probWordsGivenTopic[$key][$hash] * $count;
}
$topicsPosterior[$key] = $p;
}
sort($topicsPosterior);
$return[$i] = $topicsPosterior;
}
return $return;
}
function _ll_computeWordCounts($strings) {
$wcs = array();
foreach($strings as $string) {
$wcs[] = _ll_computeWordCount($string);
}
return $wcs;
}
function _ll_computeWordCount($string) {
$string = trim($string);
$string = explode(' ', $string);
natcasesort($string);
$hash = LL_NB_HASH_FUNCTION;
$words = array();
for($i=0, $count = count($string); $i<$count; $i++) {
$word = trim($string[$i]);
if(preg_match('/[^a-zA-Z\']/', $word))
continue;
$hash = (string) $hash($word);
if(!isset($words[$hash]))
$words[$hash] = 1; //$words[$hash] = array('word'=>$word, 'count'=>1);
else
$words[$hash]++; //$words[$hash]['count']++;
}
return $words;
}
$output = ll_naivebayes(array("Will I marry John", "Marriage is cool", "A string about Windows XP"), array("marriage", "marriage", "windows"), array("this is about marriage"));
?>
It looks like a bug see my comments in the code
function _ll_computeWordCount($string) {
$string = trim($string);
$string = explode(' ', $string);
natcasesort($string);
$hash = LL_NB_HASH_FUNCTION; // $hash = crc32
$words = array();
for($i=0, $count = count($string); $i<$count; $i++) {
$word = trim($string[$i]);
if(preg_match('/[^a-zA-Z\']/', $word))
continue;
$hash = (string) $hash($word); // 1st iteration $hash = crc32($word)
//2nd iteration $hash = 2949202($word) - fatal error
if(!isset($words[$hash]))
$words[$hash] = 1; //$words[$hash] = array('word'=>$word, 'count'=>1);
else
$words[$hash]++; //$words[$hash]['count']++;
}
return $words;
}
Try this
function _ll_computeWordCount($string) {
$string = trim($string);
$string = explode(' ', $string);
natcasesort($string);
$hash_function = LL_NB_HASH_FUNCTION;
$words = array();
for($i=0, $count = count($string); $i<$count; $i++) {
$word = trim($string[$i]);
if(preg_match('/[^a-zA-Z\']/', $word))
continue;
$hash = (string) $hash_function($word);
if(!isset($words[$hash]))
$words[$hash] = 1; //$words[$hash] = array('word'=>$word, 'count'=>1);
else
$words[$hash]++; //$words[$hash]['count']++;
}
return $words;
}

Multiple String Replace Based on Index

I need to replace multiple sections of a string based on their indices.
$string = '01234567890123456789';
$replacements = array(
array(3, 2, 'test'),
array(8, 2, 'haha')
);
$expected_result = '012test567haha0123456789';
Indices in $replacements are expected not to have overlaps.
I have been trying to write my own solution, split the original array into multiple pieces based on sections which needs to be replaced or not, and finally combine them:
echo str_replace_with_indices($string, $replacements);
// outputs the expected result '012test567haha0123456789'
function str_replace_with_indices ($string, $replacements) {
$string_chars = str_split($string);
$string_sections = array();
$replacing = false;
$section = 0;
foreach($string_chars as $char_idx => $char) {
if ($replacing != (($r_idx = replacing($replacements, $char_idx)) !== false)) {
$replacing = !$replacing;
$section++;
}
$string_sections[$section] = $string_sections[$section] ? $string_sections[$section] : array();
$string_sections[$section]['original'] .= $char;
if ($replacing) $string_sections[$section]['new'] = $replacements[$r_idx][2];
}
$string_result = '';
foreach($string_sections as $s) {
$string_result .= ($s['new']) ? $s['new'] : $s['original'];
}
return $string_result;
}
function replacing($replacements, $idx) {
foreach($replacements as $r_idx => $r) {
if ($idx >= $r[0] && $idx < $r[0]+$r[1]) {
return $r_idx;
}
}
return false;
}
Is there any more effective way to achieve the same result?
The above solution doesn't look elegant and feels quite long for string replacement.
Use this
$str = '01234567890123456789';
$rep = array(array(3,3,'test'), array(8,2,'haha'));
$index = 0;
$ctr = 0;
$index_strlen = 0;
foreach($rep as $s)
{
$index = $s[0]+$index_strlen;
$str = substr_replace($str, $s[2], $index, $s[1]);
$index_strlen += strlen($s[2]) - $s[1];
}
echo $str;

where is mistake ? php letter matrix boggle

I find theese php codes here, but codes aren't working correctly. it seems that the if(isset($words[$word])) doesn't go through as I always get an empty results array
$boggle = "fxie
amlo
ewbx
astu";
$alphabet = str_split(str_replace(array("\n", " ", "\r"), "", strtolower($boggle)));
$rows = array_map('trim', explode("\n", $boggle));
$dictionary = file("C:/dict.txt");
$prefixes = array(''=>'');
$words = array();
$regex = '/[' . implode('', $alphabet) . ']{3,}$/S';
foreach($dictionary as $k=>$value) {
$value = trim(strtolower($value));
$length = strlen($value);
if(preg_match($regex, $value)) {
for($x = 0; $x < $length; $x++) {
$letter = substr($value, 0, $x+1);
if($letter == $value) {
$words[$value] = 1;
} else {
$prefixes[$letter] = 1;
}
}
}
}
$graph = array();
$chardict = array();
$positions = array();
$c = count($rows);
for($i = 0; $i < $c; $i++) {
$l = strlen($rows[$i]);
for($j = 0; $j < $l; $j++) {
$chardict[$i.','.$j] = $rows[$i][$j];
$children = array();
$pos = array(-1,0,1);
foreach($pos as $z) {
$xCoord = $z + $i;
if($xCoord < 0 || $xCoord >= count($rows)) {
continue;
}
$len = strlen($rows[0]);
foreach($pos as $w) {
$yCoord = $j + $w;
if(($yCoord < 0 || $yCoord >= $len) || ($z == 0 && $w == 0)) {
continue;
}
$children[] = array($xCoord, $yCoord);
}
}
$graph['None'][] = array($i, $j);
$graph[$i.','.$j] = $children;
}
}
function to_word($chardict, $prefix) {
$word = array();
foreach($prefix as $v) {
$word[] = $chardict[$v[0].','.$v[1]];
}
return implode("", $word);
}
function find_words($graph, $chardict, $position, $prefix, $prefixes, &$results, $words) {
$word = to_word($chardict, $prefix);
if(!isset($prefixes[$word])) return false;
**if(isset($words[$word])) {
$results[] = $word;
}**
foreach($graph[$position] as $child) {
if(!in_array($child, $prefix)) {
$newprefix = $prefix;
$newprefix[] = $child;
find_words($graph, $chardict, $child[0].','.$child[1], $newprefix, $prefixes, $results, $words);
}
}
}
$solution = array();
find_words($graph, $chardict, 'None', array(), $prefixes, $solution);
print_r($solution);
When you call find_words() at the end, you are only passing 6 parameters
find_words($graph, $chardict, 'None', array(), $prefixes, $solution);
The variable $words, is the 7th parameter in your definition of find_words()
function find_words($graph, $chardict, $position, $prefix, $prefixes, &$results, $words) {
Hence, $words will always be empty, and isset($words[$word]) will always be false

Include these methods into my class

These are my two methods, I need to include them in my class but am unsure how to do it since I'm not an OO programmer
function gcd($x,$y)
{
do {
$rest=$x%$y;
$x=$y;
$y=$rest;
} while($rest!==0);
return $x;
}
function testCommonality($a)
{
$keys = array_keys($a[1]);
$common = array();
foreach ($keys as $key) {
$v1 = $a[0][$key];
$v2 = $a[1][$key];
if ((gcd($v1, $v2)) != 1) $a[0]['m'] *= 1.5;
}
return $a;
}
print_r($parser->algorithm->testCommonality());
I need to include those in this class, and have them operate on the output of $parser->algorithm Help is greatly GREATLY appreciated
class CSVParser
{
public $output = NULL;
public $digits = NULL;
public function __construct($file)
{
if (!file_exists($file)) {
throw new Exception("$file does not exist");
}
$this->contents = file_get_contents($file);
$this->output = array();
$this->digits = array();
}
public function parse($separatorChar1 = ',', $separatorChar2 = ';', $enclosureChar = '"', $newlineChar = "\n")
{
$lines = explode($newlineChar, $this->contents);
foreach ($lines as $line) {
if (strlen($line) == 0) continue;
$group = array();
list($part1, $part2) = explode($separatorChar2, $line);
$group[] = array_map(array($this, "trim_value"), explode($separatorChar1, $part1), array("$enclosureChar \t"));
$group[] = array_map(array($this, "trim_value"), explode($separatorChar1, $part2), array("$enclosureChar \t"));
$this->output[] = $group;
}
}
private function trim_value($value, $chars)
{
return preg_replace("#^( |" . $chars . ")+#", '', $value);
}
public function algorithm()
{
$alpha = array(
'c' => str_split('bcdfghjklmnpqrstvwxz'),
'v' => str_split('aeiouy')
);
$i = 0;
$k = 0;
foreach ($this->output as $item) {
$cnt = 0;
$this->digits[$i] = array();
foreach ($item as $part) {
$this->digits[$i][$cnt] = array();
$new = array();
foreach ($part as $str) {
$v = count(array_intersect(str_split($str), $alpha['v']));
$c = count(array_intersect(str_split($str), $alpha['c']));
$t = strlen(str_replace(' ', '', $str));
$new = array('v' => $v, 'c' => $c, 't' => $t);
$this->digits[$i][$cnt][] = $new;
}
$cnt++;
}
$i++;
}
}
}
$parser = new CSVParser("file.txt");
$parser->parse();
print_r($parser->output);
$parser->algorithm();
print_r($parser->digits);
Thanks for the help!
I know very little of PHP, but, if I understand correctly, what you are asking appears to be straight forward enough. I would have thought somebody would have already answered this.
The following may be something like what you are after:
class CSVParser
{
public $output = NULL;
public $digits = NULL;
public function __construct($file)
{
if (!file_exists($file)) {
throw new Exception("$file does not exist");
}
$this->contents = file_get_contents($file);
$this->output = array();
$this->digits = array();
}
public function parse($separatorChar1 = ',', $separatorChar2 = ';', $enclosureChar = '"', $newlineChar = "\n")
{
$lines = explode($newlineChar, $this->contents);
foreach ($lines as $line) {
if (strlen($line) == 0) continue;
$group = array();
list($part1, $part2) = explode($separatorChar2, $line);
$group[] = array_map(array($this, "trim_value"), explode($separatorChar1, $part1), array("$enclosureChar \t"));
$group[] = array_map(array($this, "trim_value"), explode($separatorChar1, $part2), array("$enclosureChar \t"));
$this->output[] = $group;
}
}
private function trim_value($value, $chars)
{
return preg_replace("#^( |" . $chars . ")+#", '', $value);
}
public function algorithm()
{
$alpha = array(
'c' => str_split('bcdfghjklmnpqrstvwxz'),
'v' => str_split('aeiouy')
);
$i = 0;
$k = 0;
foreach ($this->output as $item) {
$cnt = 0;
$this->digits[$i] = array();
foreach ($item as $part) {
$this->digits[$i][$cnt] = array();
$new = array();
foreach ($part as $str) {
$v = count(array_intersect(str_split($str), $alpha['v']));
$c = count(array_intersect(str_split($str), $alpha['c']));
$t = strlen(str_replace(' ', '', $str));
$new = array('v' => $v, 'c' => $c, 't' => $t);
$this->digits[$i][$cnt][] = $new;
}
$cnt++;
}
$i++;
}
return $this->digits;
}
private function gcd($x,$y)
{
do {
$rest=$x%$y;
$x=$y;
$y=$rest;
} while($rest!==0);
return $x;
}
public function testCommonality($a)
{
$keys = array_keys($a[1]);
$common = array();
foreach ($keys as $key) {
$v1 = $a[0][$key];
$v2 = $a[1][$key];
if ((gcd($v1, $v2)) != 1) $a[0]['m'] *= 1.5;
}
return $a;
}
}
$parser = new CSVParser("file.txt");
$parser->parse();
print_r($parser->output);
$parser->algorithm();
print_r($parser->digits);
print_r( $parser->testCommonality( $parser->digits() ) );
`

Replace string in php

I have this string:
525,294,475,215,365,745
and i need to remove 475..and comma.
and if i need to remove first number i need to remove also the next comma, also for last.
I can i do?
a regular expression?
thx
$newStr = str_replace(',475', '525,294,475,215,365,745');
Or the less error prone way:
$new = array();
$pieces = explode(',', '525,294,475,215,365,745');
foreach ($pieces as $piece) {
if ($piece != 475) {
$new[] = $piece;
}
}
$newStr = implode(',', $new);
Here's a regular expression:
$s = "525,294,475,215,365,745";
$s = preg_replace(',?475', '', $s);
$data = "525,294,475,215,365,745";
$parts = explode(',', $data);
for ($i = 0; $i < count($parts); $i++) {
if ($parts[$i] == 475) {
unset($parts[$i]);
}
}
$newdata = join(',', $parts);
<?php
$bigString = "525,294,475,215,365,745";
$pos = strpos($bigString, ",");
while($pos != false) {
$newString .= substr($bigString, 0, $pos);
$bigString = substr($bigString, $pos + 1);
$pos = strpos($bigString, ",");
}
echo $newString;
?>
function filterValue($index, &$a)
{
$key = array_search($index, $a);
if ($key != false) {
unset($a[$key]);
}
}
// Original data
$data = "525,294,475,215,365,745";
$data = explode(',', $data);
filterValue('475', $data);
$output = implode(',', $data);

Categories