I have a text file that has item numbers in it (one per line). When an item is scanned by our barcode scanner it gets placed into this text file IF it exists in the order (which is stored in an array...item numbers only, nothing else).
What's happening is that if I have the two item numbers:
C0DB-9700-W
C0DB-9700-WP
If I scan the item C0DB-9700-W first then I can scan the second item just fine, but if I scan C0DB-9700-WP first, it thinks that I've already scanned C0DB-9700-W because that item is a prefix to the item I've already scanned.
I know that strpos only checks for the first occurrence. I was using the following code:
if (strpos($file_array, $submitted ) !==FALSE) {
I switched to using:
if (preg_match('/'.$submitted.'/', $file_array)) {
I thought that by using preg_match I could overcome the problem, but apparently not. I just want PHP to check the EXACT string I give it against items in the array (which I'm getting from the file) to see if it has already been scanned or not. This isn't that hard in my mind but obviously I'm missing something here. How can I coax PHP into looking for the entire string and not giving up when it finds something that will be good enough (or at least what it thinks is good enough)?
Thanks!
Just use in_array:
if (in_array($submitted, $file_array))
FYI, your regex was missing start/end anchors (and the second argument needs to be a string, not an array):
preg_match('/^'.$submitted.'$/', $subject)
There's nothing inexact about C0DB-9700-WP containing a match for C0DB-9700-W. What you're looking for is a regular expression that ensures the string you want is an entire word by itself:
if (preg_match('/\\b'.$submitted.'\\b/', $file_array)) {
For an array of items $file_array:
if (in_array($submitted, $file_array)) {
// Do something...
}
Although in your examples, it looks like your $file_array is a string, so you'd want to do:
$file_array = explode("\n", $file_array);
Related
# Check arrary not empty
if (!empty($results)) {
$this->code($results);
// got the mail code from database
// which is PG-000001
// how do i add , like something PG-000001 ++
}
this will return a result from database , my intention is to keep adding up the code that return from my database and the update back to the database.
now it was return PG-000001, how do i make it add up and be like PG-000002 and then update it and next time it will be PG-000002 and up to 000003 and so on.
how do i add up the text PG-000001?
If all of your codes look like this, then your really shouldn’t store them that way. It appears that the PG- at the beginning is just a prefix. If you store the actual value as an integer, you can increment as much as you like.
Anyway, the solution to your question is that you will need to
split the string
increment the second part
zero-pad the second part
combine again
Here is a little test script:
$test='PG-000001';
$pattern='/(.*-)(\d+)/';
preg_match($pattern,$test,$matches);
list(,$prefix,$value)=$matches;
$value=sprintf('%06d',$value+1);
$test="$prefix$value";
print $test;
Translation:
/(.*-)(\d+)/ is the pattern that will split the string into the prefix & numeral
preg_match applies the pattern and returns the result into the array $matches.
$matches has the original string, and then the two matches
list() copies elements of the array into variables. The leading comma skips the first element
sprintf formats the data. In this case, the code 0-pads to 6 digits
the double-quoted string is a simple way of recombining your data.
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 have a 15,000 row PHP array. I need to iterate through each row to generate a 15,000 row Javascript array. Each row of the PHP array has a 5% chance of containing one or more HTML special characters like ó that I need to replace with the equivalent javascript hex. There are about 50 HTML special characters I have to look out for and replace, so I'd use str_replace(array_of_HTML_targets, array_of_hex_replacements, haystack). Is it more efficient to:
Go through each line of the PHP array, search for an ampersand, and if one exists do the search and replace (considering this will apply for only 5% of the rows)
Execute the search and replace on the entire array
Concatenate the array into one giant string and execute the search and replace on the giant string
Other idea? Please specify
Btw, reason for 15,000 PHP array is this is a data visualization app.
Since you already need to dump your PHP data into a string (probably JSON), you might as well work on the final string, like so:
$json = json_encode($your_php_array);
$unhtmlref = preg_replace_callback("/&#(x[0-9a-f]+|\d+);/",function($m) {
if( $m[1][0] == "x") $m[1] = substr($m[1],1);
else $m[1] = dechex($m[1]);
return sprintf("\\u%04s",$m[1]);
},$json);
This is safe, because HTML character codes don't have any special meaning in a JSON string.
That said, I have a function in my JavaScript "utility belt" that does something similar:
function unHTMLref(str) {
// take a string and return it, with all HTML character codes parsed
var div = document.createElement('div');
div.innerHTML = str.replace(/</g,"<");
return div.firstChild.nodeValue;
}
So basically you can either parse before, or after. Personally, I'd prefer "after" because it shifts some of the "grunt" work to the browser, allowing the server to do more important things.
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";
?>
Ok, am trying to find a character or group of characters, or something that can be used that I can explode from, since the text is user-defined, I need to be able to explode from a value that I have that can never be within the text.
How can I do this?
An example of what I'm trying to do...
$value = 'text|0||#fd9||right';
Ok,
text is something that should never change in here.
0, again not changeable
#fd9 is a user-defined string that can be anything that the user inputs...
and right sets the orientation (either left or right).
So, the problem I'm facing is this: How to explode("||", $value) so that if there is a || within the user-defined part... Example:
$value = 'text|0||Just some || text in here||right';
So, if the user places the || in the user-defined part of the string, than this messes this up. How to do this no matter what the user inputs into the string? So that it should return the following array:
array('text|0', 'Just some || text in here', 'right');
Should I be using different character(s) to explode from? If so, what can I use that the user will not be able to input into the string, or how can I check for this, and fix it? I probably shouldn't be using || in this case, but what can I use to fix this?
Also, the value will be coming from a string at first, and than from the database afterwards (once saved).
Any Ideas?
The problem of how to represent arbitrary data types as strings always runs up against exactly the problem you're describing and it has been solved in many ways already. This process is called serialization and there are many serialization formats, anything from PHP's native serialize to JSON to XML. All these formats specify how to present complex data structures as strings, including escaping rules for how to use characters that have a special meaning in the serialization format in the serialized values themselves.
From the comments:
Ok, well, basically, it's straight forward. I already outlined 13 of the other parameters and how they work in Dream Portal located here: http://dream-portal.net/topic_122.0.html so, you can see how they fit in. I'm working on a fieldset parameter that basically uses all of these parameters and than some to include multiple parameters into 1. Anyways, hope that link helps you, for an idea of what an XML file looks like for a module: http://dream-portal.net/topic_98.0.html look at the info.xml section, pay attention to the <param> tag in there, at the bottom, 2 of them.
It seems to me that a more sensible use of XML would make this a lot easier. I haven't read the whole thing in detail, but an XML element like
<param name="test_param" type="select">0:opt1;opt2;opt3</param>
would make much more sense written as
<select name="test_param">
<option default>opt1</option>
<option>opt2</option>
<option>opt3</option>
</select>
Each unique configuration option can have its own unique element namespace with custom sub-elements depending on the type of parameter you need to represent. Then there's no need to invent a custom mini-format for each possible parameter. It also allows you to create a formal XML schema (whether this will do you any good or not is a different topic, but at least you're using XML as it was meant to be used).
You can encode any user input to base64 and then use it with explode or however you wish.
print base64_encode("abcdefghijklmnopqrstuvwxyz1234567890`~!##$%^&*()_+-=[];,./?>:}{<");
serialized arrays are also not a bad idea at all. it's probably better than using a comma separated string and explode. Drupal makes good use of serialized arrays.
take a look at the PHP manual on how to use it:
serialize()
unserialize()
EDIT: New Solution
Is it a guarantee that text doesn't contain || itself?
If it doesn't, you can use substr() in combination with strpos() and strrpos() instead of explode
Here's what I usually do to get around this problem.
1) capture user's text and save it in a var $user_text;
2) run an str_replace() on $user_text to replace the characters you want to split by:
//replace with some random string the user would hopefully never enter
$modified = str_replace('||','{%^#',$user_text);
3) now you can safely explode your text using ||
4) now run an str_replace on each part of the explode, to set it back to the original user entered text
foreach($parts as &$part) {
$part = str_replace('{%^#','||',$part);
}