Where the bug of this code - php

I have a simple code that doesn't work correctly, I have a file like this:
David
Jordan
Steve
& in a simple PHP code:
$file = new SplFileObject("file.txt");
while (!$file->eof()) {
$array[]=$file->fgets();
}
$string = 'Hi , I\'M David';
if(strposa($string, $array)){
echo 'true';
} else {
echo 'false';
}
function strposa($haystack, $needle, $offset=0) {
if(!is_array($needle)) $needle = array($needle);
foreach($needle as $query) {
if(strpos($haystack, $query, $offset) !== false) return true; // stop on first true result
}
return false;
}
but this code doesn't work correctly ,
if
$string = 'Hi , I\'M David';
It's Return false but when $string change to:
$string = 'Hi , I\'M Steve';
It return True!

finally, I find three ways to fix this .
way 1 => use rtrim function:
$array[]=rtrim($file->fgets());
way 2 => use str_replace function :
$array=str_replace("\r\n","",$array);
or
$array[]=str_replace("\r\n","",$file->fgets());
way 3 => use file function :
$array = file("file.txt", FILE_IGNORE_NEW_LINES);

The output from $file->fgets() function will contain newline character \n at the end. That's why strpos() function is returning false.
You have to clear the newline character from fgets() function by using trim() function.

Related

Search for string from an array of values, then return the first value it finds as a usable variable outside of the function itself

I'm basically just trying to store or access the found string as usable variable (that can be echo'd outside of this function).
Here's the code for my function;
function strposa($haystack, $needle, $offset=0)
{
if(!is_array($needle)) $needle = array($needle);
foreach($needle as $query)
{
if(stripos($haystack, $query, $offset) !== false) return $query;
}
return false;
}
So once it finds a match, how do I then echo out the match in my html using
<?php echo $found; ?>
Here's an idea of how it's being used....
$haystack = 'May contain traces of nuts';
$needle = array('gluten','nuts','milk');
$found = strposa($haystack, $needle, $offset);
if(strposa($haystack, $needle, 0)) {
echo $found;
};
This is currently producing bool(false) using the above function.
It's kind of odd that needle is an array and not haystack, but ignoring that, you have two issues:
First, you need to return the value and not the key:
function strposa($haystack, $needle, $offset=0)
{
if(!is_array($needle)) $needle = array($needle);
foreach($needle as $query)
{
if(stripos($haystack, $query, $offset) !== false) return $query;
}
return false;
}
Second, you need to assign the return to something:
<?php $found = strposa($haystack, $needle, $offset); ?>
<?php echo $found; ?>
But since it may be returning false, you'll need to test for that in the above assignment or before echoing:
if($found = strposa($haystack, $needle, $offset)) {
echo $found;
}
Using preg_match() with piped needles in your case-insensitive regex pattern removes the need for a custom function that uses a loop AND will allow you to better customize your search if/when your terms yield false positives due to the string existing inside of the a larger/different word.
I have displayed 3 working examples. The first is without an offset and works as expected. The second is without an offset and highlights a potential pitfall with any string search method. The third uses an offset and works as expected.
$needle = array('gluten','nuts','milk');
$regex="/".implode("|",$needle)."/i";
// $regex = /gluten|nuts|milk/i
$haystack = 'May contain traces of nuts';
if(preg_match($regex,$haystack,$match)){
$found=$match[0];
}else{
$found="Not Found"; // false
}
echo "<div>Found = $found</div>";
// TRUE POSITIVE:
// Output: Found = nuts
$haystack = 'This recipe is gluten-free!';
if(preg_match($regex,$haystack,$match)){
$found=$match[0];
}else{
$found="Not Found"; // false
}
echo "<div>Found = $found</div>";
// FALSE POSITIVE:
// Output: Found = gluten
// improve your regex pattern as needed
// for instance use: $regex="/\b".implode("\b|\b",$needle)."\b/i";
// against $haystack="May contain bits of shell from coconuts";
// and it will return "Not Found" because of the word boundaries
$haystack = 'Who put nuts in my milk?!';
$offset=12; // start beyond nuts
if(preg_match($regex,substr($haystack,$offset),$match)){
$found=$match[0];
}else{
$found="Not Found"; // false
}
echo "<div>Found = $found</div>";
// TRUE POSITIVE:
// Output: Found = milk

find bad word using strpos from string

I have following php code to find bad word in a string.
It stop on first bad word found and return true.
The bad words are provided as comma separated list that is converted to array.
$paragraph = "We have fur to sell";
$badWords = "sis, fur";
$badWordsArray = explode(",", $badWords);
function strpos_arr($string, $array, $offset=0) { // Find array values in string
foreach($array as $query) {
if(strpos($string, $query, $offset) !== false) return true; // stop on first true result for efficiency
}
return false;
}
strpos_arr($paragraph, $badWordsArray);
The issue is it also returns true if bad word provided is a part of another word.
I prefer using strpos.
Please also suggest if there is any more efficient way to find bad words.
try this, with reqular expression:
$paragraph = "We have fur to sell";
$badWords = "sis, fur";
$badWordsArray = preg_split('/\s*,\s*/', $badWords, -1, PREG_SPLIT_NO_EMPTY);
var_dump($badWordsArray);
function searchBadWords($string, $array, $offset=0) { // Find array values in string
foreach ($array as $query) {
if (preg_match('/\b' . preg_quote($query, '/') . '\b/i', $string)) return true; // stop on first true result for efficiency
}
return false;
}
var_dump(searchBadWords($paragraph, $badWordsArray));
Explanation:
First. We want to correctly split our $badWords string:
$badWordsArray = preg_split('/\s*,\s*/', $badWords, -1, PREG_SPLIT_NO_EMPTY);
This way we will correctly split strings like "sis, fur" and "sis , fur" and even "sis , , fur" to an array('sis', 'fur').
Then we are performing regexp-search of exact word using \b meta-character. Which means word-boundary in terms of regular expression, that is position between a word-characted and a non-word-character.
Just include spaces in your search string.
$paragraph = "We have fur to sell";
$badWords = "sis, fur";
$badWordsArray = explode(",", $badWords);
function strpos_arr($string, $array, $offset=0) { // Find array values in string
$string = " ".$string." ";
foreach($array as $query) {
$query = " ".$query." ";
if(strpos($string, $query, $offset) !== false) return true; // stop on first true result for efficiency
}
return false;
}
strpos_arr($paragraph, $badWordsArray);

Check if string contains word in array [duplicate]

This question already has answers here:
String contains any items in an array (case insensitive)
(15 answers)
Closed 2 years ago.
This is for a chat page. I have a $string = "This dude is a mothertrucker". I have an array of badwords: $bads = array('truck', 'shot', etc). How could I check to see if $string contains any of the words in $bad?
So far I have:
foreach ($bads as $bad) {
if (strpos($string,$bad) !== false) {
//say NO!
}
else {
// YES! }
}
Except when I do this, when a user types in a word in the $bads list, the output is NO! followed by YES! so for some reason the code is running it twice through.
function contains($str, array $arr)
{
foreach($arr as $a) {
if (stripos($str,$a) !== false) return true;
}
return false;
}
1) The simplest way:
if ( in_array( 'three', ['one', 'three', 'seven'] ))
...
2) Another way (while checking arrays towards another arrays):
$keywords=array('one','two','three');
$targets=array('eleven','six','two');
foreach ( $targets as $string )
{
foreach ( $keywords as $keyword )
{
if ( strpos( $string, $keyword ) !== FALSE )
{ echo "The word appeared !!" }
}
}
can you please try this instead of your code
$string = "This dude is a mothertrucker";
$bads = array('truck', 'shot');
foreach($bads as $bad) {
$place = strpos($string, $bad);
if (!empty($place)) {
echo 'Bad word';
exit;
} else {
echo "Good";
}
}
There is a very short php script that you can use to identify bad words in a string which uses str_ireplace as follows:
$string = "This dude is a mean mothertrucker";
$badwords = array('truck', 'shot', 'ass');
$banstring = ($string != str_ireplace($badwords,"XX",$string))? true: false;
if ($banstring) {
echo 'Bad words found';
} else {
echo 'No bad words in the string';
}
The single line:
$banstring = ($string != str_ireplace($badwords,"XX",$string))? true: false;
does all the work.
You can flip your bad word array and do the same checking much faster. Define each bad word as a key of the array. For example,
//define global variable that is available to too part of php script
//you don't want to redefine the array each time you call the function
//as a work around you may write a class if you don't want global variable
$GLOBALS['bad_words']= array('truck' => true, 'shot' => true);
function containsBadWord($str){
//get rid of extra white spaces at the end and beginning of the string
$str= trim($str);
//replace multiple white spaces next to each other with single space.
//So we don't have problem when we use explode on the string(we dont want empty elements in the array)
$str= preg_replace('/\s+/', ' ', $str);
$word_list= explode(" ", $str);
foreach($word_list as $word){
if( isset($GLOBALS['bad_words'][$word]) ){
return true;
}
}
return false;
}
$string = "This dude is a mothertrucker";
if ( !containsBadWord($string) ){
//doesn't contain bad word
}
else{
//contains bad word
}
In this code we are just checking if an index exist rather than comparing bad word with all the words in the bad word list.
isset is much faster than in_array and marginally faster than array_key_exists.
Make sure none of the values in bad word array are set to null.
isset will return false if the array index is set to null.
Put and exit or die once it find any bad words, like this
foreach ($bads as $bad) {
if (strpos($string,$bad) !== false) {
//say NO!
}
else {
echo YES;
die(); or exit;
}
}
You can do the filter this way also
$string = "This dude is a mothertrucker";
if (preg_match_all('#\b(truck|shot|etc)\b#', $string )) //add all bad words here.
{
echo "There is a bad word in the string";
}
else {
echo "There is no bad word in the string";
}
Wanted this?
$string = "This dude is a mothertrucker";
$bads = array('truck', 'shot', 'mothertrucker');
foreach ($bads as $bad) {
if (strstr($string,$bad) !== false) {
echo 'NO<br>';
}
else {
echo 'YES<br>';
}
}
If you want to do with array_intersect(), then use below code :
function checkString(array $arr, $str) {
$str = preg_replace( array('/[^ \w]+/', '/\s+/'), ' ', strtolower($str) ); // Remove Special Characters and extra spaces -or- convert to LowerCase
$matchedString = array_intersect( explode(' ', $str), $arr);
if ( count($matchedString) > 0 ) {
return true;
}
return false;
}
I would go that way if chat string is not that long.
$badwords = array('mothertrucker', 'ash', 'whole');
$chatstr = 'This dude is a mothertrucker';
$chatstrArr = explode(' ',$chatstr);
$badwordfound = false;
foreach ($chatstrArr as $k => $v) {
if (in_array($v,$badwords)) {$badwordfound = true; break;}
foreach($badwords as $kb => $vb) {
if (strstr($v, $kb)) $badwordfound = true;
break;
}
}
if ($badwordfound) { echo 'You\'re nasty!';}
else echo 'GoodGuy!';
$string = "This dude is a good man";
$bad = array('truck','shot','etc');
$flag='0';
foreach($bad as $word){
if(in_array($word,$string))
{
$flag=1;
}
}
if($flag==1)
echo "Exist";
else
echo "Not Exist";

preg_replace to match all but first occurance of something?

I'm looking for a way to replace all but first occurrences of a group or some character.
For example a following random string:
+Z1A124B555ND124AB+A555
1,5,2,4,A,B and + are repeating through out the string.
124, 555 are groups of characters that are also reoccurring.
Now, let's say I want to remove every but first occurrence of 555, A and B.
What regex would be appropriate? I could think of an example replacing all:
preg_replace('/555|A|B/','',$string);
Something like ^ that, but I want to keep the first occurrence... Any ideas?
Are your strings always delimited by plus signs? Do 555, A, and B always occur in the first "group" (delimited by +)?
If so, you can split, replace and then join:
$input = '+Z1A124B555+A124AB+A555';
$array = explode('+', $input, 3); // max 3 elements
$array[2] = str_replace(array('555', 'A', 'B'), '', $array[2]);
$output = implode('+', $array);
ps. No need to use regexes, when we can use a simple str_replace
Use the preg_replace_callback function:
$replaced = array('555' => 0, 'A' => 0, 'B' => 0);
$input = '+Z1A124B555+A124AB+A555';
$output = preg_replace_callback('/555|[AB]/', function($matches) {
static $replaced = 0;
if($replaced++ == 0) return $matches[0];
return '';
}, $input);
This solution could be modified to do what you want: PHP: preg_replace (x) occurrence?
Here is a modified solution for you:
<?php
class Parser {
private $i;
public function parse($source) {
$this->i=array();
return preg_replace_callback('/555|A|B/', array($this, 'on_match'), $source);
}
private function on_match($m) {
$first=$m[0];
if(!isset($this->i[$first]))
{
echo "I'm HERE";
$this->i[$first]=1;
}
else
{
$this->i[$first]++;
}
// Return what you want the replacement to be.
if($this->i[$first]>1)
{
$result="";
}
else
{
$result=$m[0];
}
return $result;
}
}
$sample = '+Z1A124B555ND124AB+A555';
$parse = new Parser();
$result = $parse->parse($sample);
echo "Result is: [$result]\n";
?>
A more generic function that works with every pattern.
function replaceAllButFirst($pattern, $replacement, $subject) {
return preg_replace_callback($pattern,
function($matches) use ($replacement, $subject) {
static $s;
$s++;
return ($s <= 1) ? $matches[0] : $replacement;
},
$subject
);
}

Stop Words function

I have this function that returns true if one of the bad words is found in the array $stopwords
function stopWords($string, $stopwords) {
$stopwords = explode(',', $stopwords);
$pattern = '/\b(' . implode('|', $stopwords) . ')\b/i';
if(preg_match($pattern, $string) > 0) {
return true;
}
return false;
}
It seems to work fine.
The problem is that when the array $stopwords is empty ( so no bad words specified ), it always returns true, like if the empty value is recognized as a bad word and it always returns true ( I think the issue it's this but maybe is another one ).
Can anyone help me sorting out this issue?
Thanks
I would use in_array():
function stopWords($string, $stopwords) {
return in_array($string, explode(',',$stopwords));
}
This will save some time instead of the regexp.
EDIT: to match any word in the string
function stopWords($string, $stopwords) {
$wordsArray = explode(' ', $string);
$stopwordsArray = explode(',',$stopwords);
return count(array_intersect($wordsArray, $stopwordsArray)) < 1;
}
Give $stopwords as an array
function stopWords($string, $stopwords) {
//Fail in safe mode, if $stopwords is no array
if (!is_array($stopwords)) return true;
//Empty $stopwords means all is OK
if (sizeof($stopwords)<1) return false;
....
If the array $stopwords is empty, than explode(',', $stopwords) evaluates to an empty string and $pattern equals /\b( )\b/i. This is the reason why your function returns true if $stopwords is empty.
The easiest way to fix it is to add an if statement to check whether the array is empty or not.
You can put a condition like this:
if (!empty ($stopwords)) { your code} else {echo ("no bad words");}
And then ask the user or application to input some bad words.

Categories