Explode a string in php excluding the ', ' within braces - php

I have a string of this-
$str = "field1.id as field1,
DATE_SUB(field2, INTERVAL (DAYOFMONTH(field2)-1) DAY) as field2,
field3.name as field3";
Need to explode this into array with , as this:
$requiredArray = array(
0 => field1.id as field1,
1 => DATE_SUB(field2, INTERVAL (DAYOFMONTH(field2)-1) DAY) as field2
2 => field3.name as field3
);
I've tried with explode but it doesn't works:
$requiredArray = explode(', ', $str);
// doesn't work as "DATE_SUB(field2, INTERVAL ..." also gets exploded
Any trick/ideas?

Please try this
$str = "field1.id as field1,
DATE_SUB(field2, INTERVAL (DAYOFMONTH(field2)-1) DAY) as field2,
field3.name as field3";
$buffer = '';
$stack = array();
$depth = 0;
$len = strlen($str);
for ($i=0; $i<$len; $i++) {
$char = $str[$i];
switch ($char) {
case '(':
$depth++;
break;
case ',':
if (!$depth) {
if ($buffer !== '') {
$stack[] = $buffer;
$buffer = '';
}
continue 2;
}
break;
case ' ':
if (!$depth) {
$buffer .= ' ';
continue 2;
}
break;
case ')':
if ($depth) {
$depth--;
} else {
$stack[] = $buffer.$char;
$buffer = '';
continue 2;
}
break;
}
$buffer .= $char;
}
if ($buffer !== '') {
$stack[] = $buffer;
}
echo "<pre>";
print_r($stack);
echo "</pre>";

Try this :
preg_match_all('~(.*)[^(],?~', $str, $matches);

Related

Regex, delete tags not content

Good morning
I'm working on a templateclass.
I will make conditions in the tpl file like so:
#if('eee' == 'esee')
<h2>Test</h2>
#endif
#if('aaa' == 'aaa')
<h2>Test</h2>
#endif
When the condition are false are work that all hidden, but whan true so i will delete the #if('eee' == 'esee') and #endif but i do not know how.
here my function
private static function get_condition(){
$control = array();
preg_match_all('/#if\((?P<control>[^)]+)\)/', self::$viewMainContent, $control);
$matches = isset($control['control']) ? count($control['control']) : 0;
for($i = 0; $i < $matches; $i++) {
$operators = [' == ', ' != ', ' >= ', ' <= ', ' > ', ' < '];
foreach($operators as $operator){
if(preg_match('/'.$operator.'/', $control['control'][$i])){
$val = explode($operator, $control['control'][$i]);
$param = preg_grep('/\'[^"]*\'/is', $val, PREG_SET_ORDER);
$show = false;
if(count($param) == 2){
switch(trim($operator)){
case "==":
if($param[0] == $param[1]){ $show = true; }
break;
case "!=":
if($param[0] != $param[1]){ $show = true; }
break;
case ">=":
if($param[0] >= $param[1]){ $show = true; }
break;
case "<=":
if($param[0] <= $param[1]){ $show = true; }
break;
case ">":
if($param[0] > $param[1]){ $show = true; }
break;
case "<":
if($param[0] < $param[1]){ $show = true; }
break;
}
}
self::$viewMainContent = str_replace("\n", " ", self::$viewMainContent);
if(!$show){
self::$viewMainContent = preg_replace('/'.preg_quote($control[0][$i]).'(.*?)\#endif/', '', self::$viewMainContent);
} else {
//self::$viewMainContent = preg_replace('/'.preg_quote($control[0][$i]).'/', '', self::$viewMainContent);
//self::$viewMainContent = preg_replace('/#endif/', '', self::$viewMainContent);
}
}
}
}
}
How i can delete the tags without the content?
Thx
This is really not secure, but I used eval() here, just for the sake of simplicity. You can replace it with your switch() case logic. I think the one of the ways to do what you want is with preg_replace_callback():
$template = <<<'EOD'
#if('eee' == 'eee')
<h2>Test</h2>
#endif
#if('aaa' == 'aaa')
<h2>Test</h2>
#endif
EOD;
$regex = '/#if\((?P<condition>.*)\)\n*\s*(?P<content>(?s:[\=\"\s\/\<\>\w\n]*))#endif/m';
preg_match_all($regex, $template, $matches);
$template = preg_replace_callback(
$regex,
function ($matches) {
if (eval('return ' . $matches['condition'] . ';')) {
return rtrim($matches['content']);
}
return '';
},
$template
);
var_dump($template);
Here is demo.
You can also experiment with '/#if\((?P<condition>.*)\)\n*\s*(?P<content>(?s:[\=\"\s\/\<\>\w\n]*))#endif/m' regex here.

Remove comma inside quoted string in a comma separated list

I have a string
$str = '1,2,3,4,5,"6,000",7,8,9';
How can I clean it up to:
'1,2,3,4,5,6000,7,8,9'
http://php.net/str-getcsv
$items = str_getcsv($str);
$items = array_map (
function ($item) { str_replace(',', '', $item); },
$items;
);
Now if you like you can merge them together again
$str = implode(',', $items);
Try something like this (for PHP < 5.3):
$dst = array();
$str = '1,2,3,4,5,"6,000",7,8,9';
$state = false;
$buffer = '';
for ($i = 0, $lim = strlen($str); $i < $lim; $i += 1) {
$char = $str[$i];
switch ($char) {
case ',':
if (!$state) {
$dst[] = $buffer;
$buffer = '';
}
break;
case '"':
$state = !$state;
break;
default:
$buffer .= $char;
}
}
$dst[] = $buffer;
print_r($dst);
Use this:
$str = '1,2,3,4,5,"6,000",7,8,9';
$pattern='/"(\d+),(\d+)"/';
$replacement='${1}$2';
echo preg_replace($pattern, $replacement, $str );
Thanks:-)
<?php
$str = '1,2,3,4,5,"6,000",7,8,9';
echo $str;
echo str_replace('"','',$str);
?>

"like" search and highlighting in 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);
}
}

Cutting text without destroying html tags

Is there a way to do this without writing my own function?
For example:
$text = 'Test <span><a>something</a> something else</span>.';
$text = cutText($text, 2, null, 20, true);
//result: Test <span><a>something</a></span>
I need to make this function indestructible
My problem is similar to
This thread
but I need a better solution. I would like to keep nested tags untouched.
So far my algorithm is:
function cutText($content, $max_words, $max_chars, $max_word_len, $html = false) {
$len = strlen($content);
$res = '';
$word_count = 0;
$word_started = false;
$current_word = '';
$current_word_len = 0;
if ($max_chars == null) {
$max_chars = $len;
}
$inHtml = false;
$openedTags = array();
for ($i = 0; $i<$max_chars;$i++) {
if ($content[$i] == '<' && $html) {
$inHtml = true;
}
if ($inHtml) {
$max_chars++;
}
if ($html && !$inHtml) {
if ($content[$i] != ' ' && !$word_started) {
$word_started = true;
$word_count++;
}
$current_word .= $content[$i];
$current_word_len++;
if ($current_word_len == $max_word_len) {
$current_word .= '- ';
}
if (($content[$i] == ' ') && $word_started) {
$word_started = false;
$res .= $current_word;
$current_word = '';
$current_word_len = 0;
if ($word_count == $max_words) {
return $res;
}
}
}
if ($content[$i] == '<' && $html) {
$inHtml = true;
}
}
return $res;
}
But of course it won't work. I thought about remembering opened tags and closing them if they were not closed but maybe there is a better way?
This works perfectly for me:
function trimContent ($str, $trimAtIndex) {
$beginTags = array();
$endTags = array();
for($i = 0; $i < strlen($str); $i++) {
if( $str[$i] == '<' )
$beginTags[] = $i;
else if($str[$i] == '>')
$endTags[] = $i;
}
foreach($beginTags as $k=>$index) {
// Trying to trim in between tags. Trim after the last tag
if( ( $trimAtIndex >= $index ) && ($trimAtIndex <= $endTags[$k]) ) {
$trimAtIndex = $endTags[$k];
}
}
return substr($str, 0, $trimAtIndex);
}
Try something like this
function cutText($inputText, $start, $length) {
$temp = $inputText;
$res = array();
while (strpos($temp, '>')) {
$ts = strpos($temp, '<');
$te = strpos($temp, '>');
if ($ts > 0) $res[] = substr($temp, 0, $ts);
$res[] = substr($temp, $ts, $te - $ts + 1);
$temp = substr($temp, $te + 1, strlen($temp) - $te);
}
if ($temp != '') $res[] = $temp;
$pointer = 0;
$end = $start + $length - 1;
foreach ($res as &$part) {
if (substr($part, 0, 1) != '<') {
$l = strlen($part);
$p1 = $pointer;
$p2 = $pointer + $l - 1;
$partx = "";
if ($start <= $p1 && $end >= $p2) $partx = "";
else {
if ($start > $p1 && $start <= $p2) $partx .= substr($part, 0, $start-$pointer);
if ($end >= $p1 && $end < $p2) $partx .= substr($part, $end-$pointer+1, $l-$end+$pointer);
if ($partx == "") $partx = $part;
}
$part = $partx;
$pointer += $l;
}
}
return join('', $res);
}
Parameters:
$inputText - input text
$start - position of first character
$length - how menu characters we want to remove
Example #1 - Removing first 3 characters
$text = 'Test <span><a>something</a> something else</span>.';
$text = cutText($text, 0, 3);
var_dump($text);
Output (removed "Tes")
string(47) "t <span><a>something</a> something else</span>."
Removing first 10 characters
$text = cutText($text, 0, 10);
Output (removed "Test somet")
string(40) "<span><a>hing</a> something else</span>."
Example 2 - Removing inner characters - "es" from "Test "
$text = cutText($text, 1, 2);
Output
string(48) "Tt <span><a>something</a> something else</span>."
Removing "thing something el"
$text = cutText($text, 9, 18);
Output
string(32) "Test <span><a>some</a>se</span>."
Hope this helps.
Well, maybe this is not the best solution but it's everything I can do at the moment.
Ok I solved this thing.
I divided this in 2 parts.
First cutting text without destroying html:
function cutHtml($content, $max_words, $max_chars, $max_word_len) {
$len = strlen($content);
$res = '';
$word_count = 0;
$word_started = false;
$current_word = '';
$current_word_len = 0;
if ($max_chars == null) {
$max_chars = $len;
}
$inHtml = false;
$openedTags = array();
$i = 0;
while ($i < $max_chars) {
//skip any html tags
if ($content[$i] == '<') {
$inHtml = true;
while (true) {
$res .= $content[$i];
$i++;
while($content[$i] == ' ') { $res .= $content[$i]; $i++; }
//skip any values
if ($content[$i] == "'") {
$res .= $content[$i];
$i++;
while(!($content[$i] == "'" && $content[$i-1] != "\\")) {
$res .= $content[$i];
$i++;
}
}
//skip any values
if ($content[$i] == '"') {
$res .= $content[$i];
$i++;
while(!($content[$i] == '"' && $content[$i-1] != "\\")) {
$res .= $content[$i];
$i++;
}
}
if ($content[$i] == '>') { $res .= $content[$i]; $i++; break;}
}
$inHtml = false;
}
if (!$inHtml) {
while($content[$i] == ' ') { $res .= $content[$i]; $letter_count++; $i++; } //skip spaces
$word_started = false;
$current_word = '';
$current_word_len = 0;
while (!in_array($content[$i], array(' ', '<', '.', ','))) {
if (!$word_started) {
$word_started = true;
$word_count++;
}
$current_word .= $content[$i];
$current_word_len++;
if ($current_word_len == $max_word_len) {
$current_word .= '-';
$current_word_len = 0;
}
$i++;
}
if ($letter_count > $max_chars) {
return $res;
}
if ($word_count < $max_words) {
$res .= $current_word;
$letter_count += strlen($current_word);
}
if ($word_count == $max_words) {
$res .= $current_word;
$letter_count += strlen($current_word);
return $res;
}
}
}
return $res;
}
And next thing is closing unclosed tags:
function cleanTags(&$html) {
$count = strlen($html);
$i = -1;
$openedTags = array();
while(true) {
$i++;
if ($i >= $count) break;
if ($html[$i] == '<') {
$tag = '';
$closeTag = '';
$reading = false;
//reading whole tag
while($html[$i] != '>') {
$i++;
while($html[$i] == ' ') $i++; //skip any spaces (need to be idiot proof)
if (!$reading && $html[$i] == '/') { //closing tag
$i++;
while($html[$i] == ' ') $i++; //skip any spaces
$closeTag = '';
while($html[$i] != ' ' && $html[$i] != '>') { //start reading first actuall string
$reading = true;
$html[$i] = strtolower($html[$i]); //tags to lowercase
$closeTag .= $html[$i];
$i++;
}
$c = count($openedTags);
if ($c > 0 && $openedTags[$c-1] == $closeTag) array_pop($openedTags);
}
if (!$reading) //read only tag
while($html[$i] != ' ' && $html[$i] != '>') { //start reading first actuall string
$reading = true;
$html[$i] = strtolower($html[$i]); //tags to lowercase
$tag .= $html[$i];
$i++;
}
//skip any values
if ($html[$i] == "'") {
$i++;
while(!($html[$i] == "'" && $html[$i-1] != "\\")) {
$i++;
}
}
//skip any values
if ($html[$i] == '"') {
$i++;
while(!($html[$i] == '"' && $html[$i-1] != "\\")) {
$i++;
}
}
if ($reading && $html[$i] == '/') { //self closed tag
$tag = '';
break;
}
}
if (!empty($tag)) $openedTags[] = $tag;
}
}
while (count($openedTags) > 0) {
$tag = array_pop($openedTags);
$html .= "</$tag>";
}
}
It's not idiot proof but tinymce will clear this thing out so further cleaning is not necessary.
It may be a little long but i don't think it will eat a lot of resources and it should be faster than regex.

php find number of occurances (number of times)

can someone help with this?
I need the following function to do this...
$x = 'AAAABAA';
$x2 = 'ABBBAA';
function foo($str){
//do something here....
return $str;
}
$x3 = foo($x); //output: A4B1A2
$x4 = foo($x2);//output: A1B3A2
substr_count is your friend
or rather this
function foo($str) {
$out = '';
preg_match_all('~(.)\1*~', $str, $m, PREG_SET_ORDER);
foreach($m as $p) $out .= $p[1] . strlen($p[0]);
return $out;
}
function foo($str) {
$s = str_split($str);
if (sizeof($s) > 0) {
$current = $s[0];
$output = $current;
$count = 0;
foreach ($s as $char) {
if ($char != $current ) {
$output .= $count;
$current = $char;
$output .= $current;
$count = 1;
}
else {
$count++;
}
}
$output .= $count;
return $output;
}
else
return "";
}

Categories