I have one array which contains multiple strings. I have another array which contain also strings but they are shorter. My goal is to check is there any partial match in the bigger array for every item from the smaller array. However preg_match doesnt work at all with variables. If I put raw input everything seems fine but otherwise results is false. I have tried almost every possible regex combination but without success. Sample code:
//Lets say $needle is 3333 and bigPatern has 10 records with 10 digits each, for example third record is 5125433331. I want to perform the partial match and get true
$needle = $smlPattern[0]; //debugging with first item from smaller array
$needle2 = "/$needle/"; // I tried [$needle], ^..&, to concatenate and etc
foreach ($bigPatern as $val)
{
if (preg_match($needle2, $val))
{
echo "YES";
}
}
Any tips what Im doing wrong?
Please escape your regex input!
$needle2 = "/".preg_quote($needle,'/')."/"; //
Don't blindly add user input to your regex, much for the same reason you need to escape user input in SQL queries. In regex, the biggest issue is usually the ReDoS problem, where a malicious user can create a specially crafted regex that will use hours, or more, to execute, stealing all the CPU from your server.
Main wrong thing in your example is to use regexp for checking the presence of a string. There is a strpos function for that.
if ( strpos($bigOne, $smallOne) !== false ) {
echo "bigOne contains smallOne";
}
You can even use strpos function to achieve the same purpose. It finds the position of the first occurrence of a substring in a string, and returns false if no match is found.
$needle = $smlPattern[0];
$needle2 = "needle";
foreach ($bigPatern as $val){
if (strpos($val, $needle2) !== false){
echo "YES";
}
}
Related
I am trying to learn PHP while I write a basic application. I want a process whereby old words get put into an array $oldWords = array(); so all $words, that have been used get inserted using array_push(oldWords, $words).
Every time the code is executed, I want a process that finds a new word from $wordList = array(...). However, I don't want to select any words that have already been used or are in $oldWords.
Right now I'm thinking about how I would go about this. I've been considering finding a new word via $wordChooser = rand (1, $totalWords); I've been thinking of using an if/else statement, but the problem is if array_search($word, $doneWords) finds a word, then I would need to renew the word and check it again.
This process seems extremely inefficient, and I'm considering a loop function but, which one, and what would be a good way to solve the issue?
Thanks
I'm a bit confused, PHP dies at the end of the execution of the script. However you are generating this array, could you also not at the same time generate what words haven't been used from word list? (The array_diff from all words to used words).
Or else, if there's another reason I'm missing, why can't you just use a loop and quickly find the first word in $wordList that's not in $oldWord in O(n)?
function generate_new_word() {
foreach ($wordList as $word) {
if (in_array($word, $oldWords)) {
return $word; //Word hasn't been used
}
}
return null; //All words have been used
}
Or, just do an array difference (less efficient though, since best case is it has to go through the entire array, while for the above it only has to go to the first word)
EDIT: For random
$newWordArray = array_diff($allWords, $oldWords); //List of all words in allWords that are not in oldWords
$randomNewWord = array_rand($newWordArray, 1);//Will get a new word, if there are any
Or unless you're interested in making your own datatype, the best case for this could possibly be in O(log(n))
I need some help with strpos().
Need to build a way to match any URL that contains /apple-touch but also need to keep specifics matching, such as "/favicon.gif" etc
At the moment, the matches are listed out individually as part of an array:
<?php
$errorurl = $_SERVER['REQUEST_URI'];
$blacklist = array("/favicon.gif", "/favicon.png", "/apple-touch-icon-precomposed.png", "/apple-touch-icon.png", "/apple-touch-icon-72x72-precomposed.png", "/apple-touch-icon-72x72.png", "/apple-touch-icon-114x114-precomposed.png", "/apple-touch-icon-114x114.png", "/apple-touch-icon-57x57-precomposed.png", "/apple-touch-icon-57x57.png", "/crossdomain.xml");
if (in_array($errorurl, $blacklist)) { // do nothing }
else { // send an email about error }
?>
Any ideas?
Many thanks for help
Instead of a regex, you could also remove all occurrences of your blacklist items with str_replace and compare the new string to the old one:
if ( str_replace($blacklist, '', $errorurl) !== $errorurl )
{
// do nothing
}
else
{
// send an email about error
}
If you want to use regex for this, and you want a single regex string that will capture all the values in your existing blacklist plus match any apple-touch string, then something like this would do it.
if(preg_match('/^\/(favicon|crossdomain|apple-touch.*)\.(gif|png|xml)$/',$_SERVER['REQUEST_URI']) {
//matched the blacklist!
}
To be honest, though, that's far more complex than you need.
I'd say you'd be better off keeping the specific values like favicon.gif etc in the blacklist array you already have; it'd make it a lot easier when you come to adding more items to the list.
I'd only consider using regex for the apple-touch values, since you want to block any variant of them. But even with that, it would likely be simpler if you used strpos().
I have a header that basically says something like this:
"
Forum
A great place for support.
"
And I need it to display on certain pages of my site, the ones related to the forum.
However on other pages I might want a header like:
"
Donate
Help keep us online.
"
The adresses on the forum part of the site would be similar to these.
http://localhost/index.php?p=/discussions
http://localhost/index.php?p=/activity
http://localhost/index.php?p=/discussion/6/oh-dear#Item_1
And the donate one might be like this:
http://localhost/index.php?p=/plugin/page/donate
So I need some way to have a script that goes
if url has (discussions, activity, discussion)
then use this header
"<b>Forum<b> <br> a great place for support
if else url has (donate)
then use this header
"<b>Donate<b> <br> help keep us online
else
use this header
"<b>Website<b> <br> this is our website
Use the Javascript location object:
url = location.href;
if (url.indexOf('discussions') && url.indexOf('activity') && url.indexOf('discussion')) {
document.getElementById('parent').appendChild(child-element);
else if (url.indexOf('donate')) {
document.getElementById('parent').appendChild(other-child-element);
}
else {
document.getElementById('parent').appendChild(another-child-element);
}
A function like this might help.
And if you don't know how to get variable from url, use $_GET['p']
function contains($substring, $string) {
$pos = strpos($string, $substring);
if($pos === false) {
// string needle NOT found in haystack
return false;
}
else {
// string needle found in haystack
return true;
}
}
Another (more elegant) serverside solution for you... If your URL's are always appearing with the "path" in the p parameter, you could utilize PHP's explode() and in_array() functions to make your code a little more easy to handle. Take this URL for example -
http://localhost/index.php?p=/plugin/page/donate
If we execute an explode() function on the $_GET['p'] variable, we'll get an array like this -
Array(
'plugin',
'page',
'donate'
)
Now you can execute an in_array() function to see if the string you are looking for exists in this array -
if (in_array('form',explode($_GET['p']){
// we are in the forum!
}
References -
in_array()
explode()
If you would like to do this serverside, you could always use PHP's strpos() function. It will return the location of a string within another. So all you would have to do is examine the $_SERVER['query_string'] variable and execute an strpos() search -
if (strpos($_SERVER['QUERY_STRING'],'forum')) >= 0){
// forum appears in the query string!
}
The strpos() function returns the index of the string you are searching, so remember that 0 is a valid index. When strpos() does not find a match. it will return false.
Here what I'm doing is examining one of the $_SERVER variable, they contain all sorts of information about the server and what it's current parameters are. One of these is the query string - that's all the text that comes after the ? in the URL. Once I have that, the strpos() function will search for something in that value.
I have a variable like this:
33,100,200
I need to detect if it contains a specific number, say
if(var contains '33'){
do stuff
}
But it has to not work if say they didn't have 333 in the variable the above statement shouldn't validate the if statement.
Edit: This is a string not an array.
Either explode & in_array route, or preg_match('/(?<![0-9])33(?![0-9])/',$string) route, I prefer the first.
I dont quite understand the second part of your question, but this may be the code you're looking for:
if(strpos($var, '33') !== false) {
// do stuff
}
Edit Oh, now I think i get what you're looking for
if(in_array('33', explode(',', $var)) {
// do stuff
}
Let's say I have text file Data.txt with:
26||jim||1990
31||Tanya||1942
19||Bruce||1612
8||Jim||1994
12||Brian||1988
56||Susan||2201
and it keeps going.
It has many different names in column 2.
Please tell me, how do I get the count of unique names, and how many times each name appears in the file using PHP?
I have tried:
$counts = array_count_values($item[1]);
echo $counts;
after exploding ||, but it does not work.
The result should be like:
jim-2,
tanya-1,
and so on.
Thanks for any help...
Read in each line, explode using the delimiter (in this case ||), and add it to an array if it does not already exist. If it does, increment the count.
I won't write the code for you, but here a few pointers:
fread reads in a line
explode will split the line based on a delimiter
use in_array to check if the name has been found before, and to determine whether you need to add the name to the array or just increment the count.
Edit:
Following Jon's advice, you can make it even easier for you.
Read in line-by-line, explode by delimiter and dump all the names into an array (don't worry about checking if it already exists). After you're done, use array_count_values to get every unique name and its frequency.
Here's my take on this:
Use file to read the data file, producing an array where each element corresponds to a line in the input.
Use array_filter with trim as the filter function to remove blank lines from this array. This takes advantage that trim returns a string having removed whitespace from both ends of its argument, leaving the empty string if the argument was all whitespace to begin with. The empty string converts to boolean false -- thus making array_filter disregard lines that are all whitespace.
Use array_map with a callback that involves calling explode to split each array element (line of text) into three parts and returning the second of these. This will produce an array where each element is just a name.
Use array_map again with strtoupper as the callback to convert all names to uppercase so that "jim" and "JIM" will count as the same in the next step.
Finally, use array_count_values to get the count of occurrences for each name.
Code, taking things slowly:
function extract_name($line) {
// The -1 parameter (available as of PHP 5.1.0) makes explode return all elements
// but the last one. We want to do this so that the element we are interested in
// (the second) is actually the last in the returned array, enabling us to pull it
// out with end(). This might seem strange here, but see below.
$parts = explode('||', $line, -1);
return end($parts);
}
$lines = file('data.txt'); // #1
$lines = array_filter($lines, 'trim'); // #2
$names = array_map('extract_name', $lines); // #3
$names = array_map('strtoupper', $names); // #4
$counts = array_count_values($names); // #5
print_r($counts); // to see the results
There is a reason I chose to do this in steps where each steps involves a function call on the result of the previous step -- that it's actually possible to do it in just one line:
$counts = array_count_values(
array_map(function($line){return strtoupper(end(explode('||', $line, -1)));},
array_filter(file('data.txt'), 'trim')));
print_r($counts);
See it in action.
I should mention that this might not be the "best" way to solve the problem in the sense that if your input file is huge (in the ballpark of a few million lines) this approach will consume a lot of memory because it's reading all the input in memory at once. However, it's certainly convenient and unless you know that the input is going to be that large there's no point in making life harder.
Note: Senior-level PHP developers might have noticed that I 'm violating strict standards here by feeding the result of explode to a function that accepts its argument by reference. That's valid criticism, but in my defense I am trying to keep the code as short as possible. In production it would be indeed better to use $a = explode(...); return $a[1]; although there will be no difference as regards the result.
While I do feel that this website's purpose is to answer questions and not do homework assignments, I don't acknowledge the assumption that you are doing your homework, since that fact has not been provided. I personally learned how to program by example. We all learn our own ways, so here is what I would do if I were to attempt to answer your question as accurately as possible, based on the information you have provided.
<?php
$unique_name_count = 0;
$names = array();
$filename = 'Data.txt';
$pointer = fopen($filename,'r');
$contents = fread($pointer,filesize($filename));
fclose($pointer);
$lines = explode("\n",$contents);
foreach($lines as $line)
{
$split_str = explode('|',$line);
if(isset($split_str[2]))
{
$name = strtolower($split_str[2]);
if(!in_array($name,$names))
{
$names[] = $name;
$unique_name_count++;
}
}
}
echo $unique_name_count.' unique name'.(count($unique_name_count) == 1 ? '' : 's').' found in '.$filename."\n";
?>