php bad words replacement with stars and output array - php

Following php function is being used to replace bad words with starts but I need one additional parameters that will describe either bad words found or not .
$badwords = array('dog', 'dala', 'bad3', 'ass');
$text = 'This is a dog. . Grass. is good but ass is bad.';
print_r( filterBadwords($text,$badwords));
function filterBadwords($text, array $badwords, $replaceChar = '*') {
$repu = preg_replace_callback(array_map(function($w) { return '/\b' . preg_quote($w, '/') . '\b/i'; }, $badwords),
function($match) use ($replaceChar) {
return str_repeat($replaceChar, strlen($match[0])); },
$text
);
return array('error' =>'Match/No Match', 'text' => $repu );
}// Func
Output if badwords found should be like
Array ( [error] => Match[text] => Bad word dog match. )
If no badwords found then
Array ( [error] => No Match[text] => Bad word match. )

You can use the following:
function filterBadwords($text, array $badwords, $replaceChar = '*') {
//new bool var to see if there was any match
$matched = false;
$repu = preg_replace_callback(array_map(
function($w)
{
return '/\b' . preg_quote($w, '/') . '\b/i';
}, $badwords),
//pass the $matched by reference
function($match) use ($replaceChar, &$matched)
{
//if the $match array is not empty update $matched to true
if(!empty($match))
{
$matched = true;
}
return str_repeat($replaceChar, strlen($match[0]));
}, $text);
//return response based on the bool value of $matched
if($matched)
{
$return = array('error' =>'Match', 'text' => $repu );
}
else
{
$return = array('error' =>'No Match', 'text' => $repu );
}
return $return;
}
This uses reference and if condition to see if there were any matches and then returns response based on that.
Output(if matched):
array (size=2)
'error' => string 'Match' (length=5)
'text' => string 'This is a ***. . Grass. is good but *** is bad.'
Output(if none matched):
array (size=2)
'error' => string 'No Match' (length=8)
'text' => string 'This is a . . Grass. is good but is bad.'

<?php
$badwords = array('dog', 'dala', 'bad3', 'ass');
$text = 'This is a dog. . Grass. is good but ass is bad.';
$res=is_badword($badwords,$text);
echo "<pre>"; print_r($res);
function is_badword($badwords, $text)
{
$res=array('No Error','No Match');
foreach ($badwords as $name) {
if (stripos($text, $name) !== FALSE) {
$res=array($name,'Match');
return $res;
}
}
return $res;
}
?>
Output:
Array
(
[0] => dog
[1] => Match
)

Related

PHP Regular Expression preg_match from Array with Multine doesn't match all block

Wondering if anyone out there can help me with the following regular expression, i can't match the block multine CF.{Coordonnees Abonne}: when used in PHP's preg_match function.
What is weird is when I do regex online it seems to work despite the block is in another group regex101 example
Here is the code : source code
<?php
$response = array(
1 => 'CF.{Temps}: 1',
2 => 'CF.{Etat}: return',
3 => 'CF.{Code}: 2',
4 => 'CF.{Values}: plaque',
5 => '',
6 => 'CF.{Coordonnees}: LA PERSONNE',
7 => ' ',
8 => ' 10000 LA VILLE',
9 => ' ',
10 => ' 0500235689',
11 => ' 0645788923',
12 => ' Login : test#mail.com',
13 => ' Password : PassWord!',
14 => '',
15 => 'CF.{Groupe}: 3',
16 => 'CF.{Date}: 4',
);
print_r(parseResponseBody($response));
function parseResponseBody(array $response, $delimiter = ':')
{
$responseArray = array();
$lastkey = null;
foreach ($response as $line) {
if(preg_match('/^([a-zA-Z0-9]+|CF\.{[^}]+})' . $delimiter . '\s(.*)|([a-zA-Z0-9].*)$/', $line, $matches)) {
$lastkey = $matches[1];
$responseArray[$lastkey] = $matches[2];
}
}
return $responseArray;
}
?>
Output :
Array
(
[CF.{Temps}] => 1
[CF.{Etat}] => return
[CF.{Code}] => 2
[CF.{Values}] => plaque
[CF.{Coordonnees}] => LA PERSONNE
[] =>
[CF.{Groupe}] => 3
[CF.{Date}] => 4
)
And there is the wanted final result that i need to extract :
Array
(
[CF.{Temps}] => 1
[CF.{Etat}] => return
[CF.{Code}] => 2
[CF.{Values}] => plaque
[CF.{Coordonnees}] => LA PERSONNE
10000 LA VILLE
0500235689
0645788923
Login : test#mail.com
Password : PassWord!
[CF.{Groupe}] => 3
[CF.{Date}] => 4
)
You have to check if current value at iteration starts with a block or not. Not both at same time though:
function parseResponseBody(array $response, $delimiter = ':') {
$array = [];
$lastIndex = null;
foreach ($response as $line) {
if (preg_match('~^\s*(CF\.{[^}]*})' . $delimiter . '\s+(.*)~', $line, $matches))
$array[$lastIndex = $matches[1]] = $matches[2];
elseif ((bool) $line)
$array[$lastIndex] .= PHP_EOL . $line;
}
return $array;
}
Live demo
I would do that this way:
function parse($response, $del=':', $nl="\n") {
$pattern = sprintf('~(CF\.{[^}]+})%s \K.*~A', preg_quote($del, '~'));
foreach ($response as $line) {
if ( preg_match($pattern, $line, $m) ) {
if ( !empty($key) )
$result[$key] = rtrim($result[$key]);
$key = $m[1];
$result[$key] = $m[0];
} else {
$result[$key] .= $nl . $line;
}
}
return $result;
}
var_export(parse($response));
demo
The key is stored in the capture group 1 $m[1] but the whole match $m[0] returns only the value part (the \K feature discards all matched characters on its left from the match result). When the pattern fails, the current line is appended for the last key.
The regex is fine, you just need to handle the case when there is no key:
function parseResponseBody(array $response, $delimiter = ':')
{
$responseArray = array();
$key = null;
foreach ($response as $line) {
if(preg_match('/^([a-zA-Z0-9]+|CF\.{[^}]+})' . $delimiter . '\s(.*)|([a-zA-Z0-9].*)$/', $line, $matches)) {
$key = $matches[1];
if(empty($key)){
$key = $lastKey;
$responseArray[$key] .= PHP_EOL . $matches[3];
}else{
$responseArray[$key] = $matches[2];
}
$lastKey = $key;
}
}
return $responseArray;
}
https://3v4l.org/rFIbk

PHP get array of search terms from string

Is there an easy way to parse a string for search terms including negative terms?
'this -that "the other thing" -"but not this" "-positive"'
would change to
array(
"positive" => array(
"this",
"the other thing",
"-positive"
),
"negative" => array(
"that",
"but not this"
)
)
so those terms could be used to search.
The code below will parse your query string and split it up into positive and negative search terms.
// parse the query string
$query = 'this -that "-that" "the other thing" -"but not this" ';
preg_match_all('/-*"[^"]+"|\S+/', $query, $matches);
// sort the terms
$terms = array(
'positive' => array(),
'negative' => array(),
);
foreach ($matches[0] as $match) {
if ('-' == $match[0]) {
$terms['negative'][] = trim(ltrim($match, '-'), '"');
} else {
$terms['positive'][] = trim($match, '"');
}
}
print_r($terms);
Output
Array
(
[positive] => Array
(
[0] => this
[1] => -that
[2] => the other thing
)
[negative] => Array
(
[0] => that
[1] => but not this
)
)
For those looking for the same thing I have created a gist for PHP and JavaScript
https://gist.github.com/UziTech/8877a79ebffe8b3de9a2
function getSearchTerms($search) {
$matches = null;
preg_match_all("/-?\"[^\"]+\"|-?'[^']+'|\S+/", $search, $matches);
// sort the terms
$terms = [
"positive" => [],
"negative" => []
];
foreach ($matches[0] as $i => $match) {
$negative = ("-" === $match[0]);
if ($negative) {
$match = substr($match, 1);
}
if (($match[0] === '"' && substr($match, -1) === '"') || ($match[0] === "'" && substr($match, -1) === "'")) {
$match = substr($match, 1, strlen($match) - 2);
}
if ($negative) {
$terms["negative"][] = $match;
} else {
$terms["positive"][] = $match;
}
}
return $terms;
}

How to Split/explode a string by lasr occurance of dot in php?

Hii Friends,
I have strings in php like
abc.com
abc.name.com
abc.xyz.name.org
Now i want to split above domain name(Bold text) as
string1=abc string2=com
string1=abc string2=name.com
string1=abc.xyz string2=name.org
Means i want to split user name and domain name.
So please help me.
You can try with:
$inputs = ['abc.com', 'abc.name.com', 'abc.xyz.name.org'];
foreach ($inputs as $input) {
$parts = explode('.', $input);
$right = [array_pop($parts)];
if (count($parts) > 1) {
$right[] = array_pop($parts);
}
$output = [
'left' => implode('.', $parts),
'right' => implode('.', $right),
];
var_dump($output);
}
Outputs:
array (size=2)
'left' => string 'abc' (length=3)
'right' => string 'com' (length=3)
array (size=2)
'left' => string 'abc' (length=3)
'right' => string 'com.name' (length=8)
array (size=2)
'left' => string 'abc.xyz' (length=7)
'right' => string 'org.name' (length=8)
Use array_pop() function after explode():
$vars = explode('.', $string);
if ( count($vars) == 3 ) {
$string2 = $vars[1] . '.' . $vars[2];
$string1 = $vars[0];
}
if ( count($vars) == 2 ) {
$string2 = $vars[1];
$string1 = $vars[0];
}
// Or you may use
$vars = explode('.', $string);
if ( count($vars) == 3 ) {
$string2 = $vars[1] . '.' . $vars[2];
$string1 = $vars[0];
}
if ( count($vars) == 2 ) {
$string2 = array_pop($vars);
$string1 = array_pop($vars);
}
Check pop and explode in php.net
http://php.net/manual/en/function.array-pop.php
http://php.net/manual/en/function.explode.php
This should do the trick. I tried to make it as verbose as possible. Online test
<?php
function get_last_dot_occurence ($url ) {
$fullArray = explode('.', $url);
$newArray = "";
switch (count($fullArray)) {
case 0:
break;
case 1:
$newArray = $url;
break;
case 2:
$newArray = array("string1" => $fullArray[0], "string2" => $fullArray[1]);
break;
default:
$string1 = "";
for ($i=0; $i < count($fullArray)-2; $i++) {
$string1 .= $fullArray[$i];
if($i != count($fullArray)-3)
$string1 .= '.';
}
$string2 = $fullArray[count($fullArray)-2].'.'.$fullArray[count($fullArray)-1];
$newArray = array("string1" => $string1, "string2" => $string2);
break;
}
return $newArray;
}
print_r(get_last_dot_occurence("abc.com"));
print_r(get_last_dot_occurence("abc.name.com"));
print_r(get_last_dot_occurence("abc.xyz.name.org"));

Array: set value using dot notation?

Looking into Kohana documentation, i found this really usefull function that they use to get values from a multidimensional array using a dot notation, for example:
$foo = array('bar' => array('color' => 'green', 'size' => 'M'));
$value = path($foo, 'bar.color', NULL , '.');
// $value now is 'green'
Im wondering if there is a way to set the an array value in the same way:
set_value($foo, 'bar.color', 'black');
The only way i found to do that is re-building the array notation ($array['bar']['color']) and then set the value.. using eval.
Any idea to avoid eval?
function set_val(array &$arr, $path,$val)
{
$loc = &$arr;
foreach(explode('.', $path) as $step)
{
$loc = &$loc[$step];
}
return $loc = $val;
}
Sure it's possible.
The code
function set_value(&$root, $compositeKey, $value) {
$keys = explode('.', $compositeKey);
while(count($keys) > 1) {
$key = array_shift($keys);
if(!isset($root[$key])) {
$root[$key] = array();
}
$root = &$root[$key];
}
$key = reset($keys);
$root[$key] = $value;
}
How to use it
$foo = array();
set_value($foo, 'bar.color', 'black');
print_r($foo);
Outputs
Array
(
[bar] => Array
(
[color] => black
)
)
See it in action.
Look at https://gist.github.com/elfet/4713488
$dn = new DotNotation(['bar'=>['baz'=>['foo'=>true]]]);
$value = $dn->get('bar.baz.foo'); // $value == true
$dn->set('bar.baz.foo', false); // ['foo'=>false]
$dn->add('bar.baz', ['boo'=>true]); // ['foo'=>false,'boo'=>true]
That way you can set the following values ​​more than once to the same variable.
You can make these two ways (by static variable and reference variable):
<?php
function static_dot_notation($string, $value)
{
static $return;
$token = strtok($string, '.');
$ref =& $return;
while($token !== false)
{
$ref =& $ref[$token];
$token = strtok('.');
}
$ref = $value;
return $return;
}
$test = static_dot_notation('A.1', 'A ONE');
$test = static_dot_notation('A.2', 'A TWO');
$test = static_dot_notation('B.C1', 'C ONE');
$test = static_dot_notation('B.C2', 'C TWO');
$test = static_dot_notation('B.C.D', 'D ONE');
var_export($test);
/**
array (
'A' =>
array (
1 => 'A ONE',
2 => 'A TWO',
),
'B' =>
array (
'C1' => 'C ONE',
'C2' => 'C TWO',
'C' =>
array (
'D' => 'D ONE',
),
),
*/
function reference_dot_notation($string, $value, &$array)
{
static $return;
$token = strtok($string, '.');
$ref =& $return;
while($token !== false)
{
$ref =& $ref[$token];
$token = strtok('.');
}
$ref = $value;
$array = $return;
}
reference_dot_notation('person.name', 'Wallace', $test2);
reference_dot_notation('person.lastname', 'Maxters', $test2);
var_export($test2);
/**
array (
'person' =>
array (
'name' => 'Wallace',
'lastname' => 'Maxters',
),
)
*/
I created a small class just for this!
http://github.com/projectmeta/Stingray
$stingray = new StingRay();
//To Get value
$stingray->get($array, 'this.that.someother'):
//To Set value
$stingray->get($array, 'this.that.someother', $newValue):
Updated #hair resins' answer to cater for:
When a sub-path already exists, or
When a sub-path is not an array
function set_val(array &$arr, $path,$val)
{
$loc = &$arr;
$path = explode('.', $path);
foreach($path as $step)
{
if ( ! isset($loc[$step]) OR ! is_array($loc[$step]))
$loc = &$loc[$step];
}
return $loc = $val;
}
None of the examples here worked for me, so I came up with a solution using eval() (read about the risks here, but if you don't use user data, it shouldn't be much of an issue). The if-clause in the set-method allows you to push your item onto a new or existing array at that location ($location[] = $item).
class ArrayDot {
public static function get(array &$array, string $path, string $delimiter = '.') {
return eval("return ".self::getLocationCode($array, $path, $delimiter).";");
}
public static function set(array &$array, string $path, $item, string $delimiter = '.') : void {
//if the last character is a delimiter, allow pushing onto a new or existing array
$add = substr($path, -1) == $delimiter ? '[]': '';
eval(self::getLocationCode($array, $path, $delimiter).$add." = \$item;");
}
public static function unset(array &$array, $path, string $delimiter = '.') : void {
if (is_array($path)) {
foreach($path as $part) {
self::unset($array, $part, $delimiter);
}
}
else {
eval('unset('.self::getLocationCode($array, $path, $delimiter).');');
}
}
public static function isSet(array &$array, $path, string $delimiter = '.') : bool {
if (is_array($path)) {
foreach($path as $part) {
if (!self::isSet($array, $part, $delimiter)) {
return false;
}
}
return true;
}
return eval("return isset(".self::getLocationCode($array, $path, $delimiter).");");
}
private static function getLocationCode(array &$array, string $path, string $delimiter) : string {
$path = rtrim($path, $delimiter); //Trim trailing delimiters
$escapedPathParts = array_map(function ($s) { return str_replace('\'', '\\\'', $s); }, explode($delimiter, $path));
return "\$array['".implode("']['", $escapedPathParts)."']";
}
}
Example usage:
echo '<pre>';
$array = [];
ArrayDot::set($array, 'one.two.three.', 'one.two.three.');
ArrayDot::set($array, 'one.two.three.four.', 'one.two.three.four.');
ArrayDot::set($array, 'one.two.three.four.', 'one.two.three.four. again');
ArrayDot::set($array, 'one.two.three.five.', 'one.two.three.five.');
ArrayDot::set($array, 'one.two.three.direct set', 'one.two.three.direct set');
print_r($array);
echo "\n";
echo "one.two.three.direct set: ".print_r(ArrayDot::get($array, 'one.two.three.direct set'), true)."\n";
echo "one.two.three.four: ".print_r(ArrayDot::get($array, 'one.two.three.four'), true)."\n";
Output:
Array
(
[one] => Array
(
[two] => Array
(
[three] => Array
(
[0] => one.two.three.
[four] => Array
(
[0] => one.two.three.four.
[1] => one.two.three.four. again
)
[five] => Array
(
[0] => one.two.three.five.
)
[direct set] => one.two.three.direct set
)
)
)
)
one.two.three.direct set: one.two.three.direct set
one.two.three.four: Array
(
[0] => one.two.three.four.
[1] => one.two.three.four. again
)

Parse RFC 822 compliant addresses in a TO header

I would like to parse an email address list (like the one in a TO header) with preg_match_all to get the user name (if exists) and the E-mail. Something similar to mailparse_rfc822_parse_addresses or Mail_RFC822::parseAddressList() from Pear, but in plain PHP.
Input :
"DOE, John \(ACME\)" <john.doe#somewhere.com>, "DOE, Jane" <jane.doe#somewhere.com>
Output :
array(
array(
'name' => 'DOE, John (ACME)',
'email' => 'john.doe#somewhere.com'
),
array(
'name' => 'DOE, Jane',
'email' => 'jane.doe#somewhere.com'
)
)
Don't need to support strange E-mail format (/[a-z0-9._%-]+#[a-z0-9.-]+.[a-z]{2,4}/i for email part is OK).
I can't use explode because the comma can appear in the name. str_getcsv doesn't work, because I can have:
DOE, John \(ACME\) <john.doe#somewhere.com>
as input.
Update:
For the moment, I've got this :
public static function parseAddressList($addressList)
{
$pattern = '/^(?:"?([^<"]+)"?\s)?<?([^>]+#[^>]+)>?$/';
if (preg_match($pattern, $addressList, $matches)) {
return array(
array(
'name' => stripcslashes($matches[1]),
'email' => $matches[2]
)
);
} else {
$parts = str_getcsv($addressList);
$result = array();
foreach($parts as $part) {
if (preg_match($pattern, $part, $matches)) {
$result[] = array(
'name' => stripcslashes($matches[1]),
'email' => $matches[2]
);
}
}
return $result;
}
}
but it fails on:
"DOE, \"John\"" <john.doe#somewhere.com>
I need to test on back reference the \" but I don't remember how to do this.
Finally I did it:
public static function parseAddressList($addressList)
{
$pattern = '/^(?:"?((?:[^"\\\\]|\\\\.)+)"?\s)?<?([a-z0-9._%-]+#[a-z0-9.-]+\\.[a-z]{2,4})>?$/i';
if (($addressList[0] != '<') and preg_match($pattern, $addressList, $matches)) {
return array(
array(
'name' => stripcslashes($matches[1]),
'email' => $matches[2]
)
);
} else {
$parts = str_getcsv($addressList);
$result = array();
foreach($parts as $part) {
if (preg_match($pattern, $part, $matches)) {
$item = array();
if ($matches[1] != '') $item['name'] = stripcslashes($matches[1]);
$item['email'] = $matches[2];
$result[] = $item;
}
}
return $result;
}
}
But I'm not sure it works for all cases.
I don't know that RFC, but if the format is always as you showed then you can try something like:
preg_match_all("/\"([^\"]*)\"\\s+<([^<>]*)>/", $string, $matches);
print_r($matches);

Categories