I have some html menu, the max width is 990px. now i want to print this menu from an array, and make these menu list(<li>) in one line. remove the padding space or each menu list, for a conserved calculation, how to limit the total words within 200 characters from a foreach? I have no good idea, in my code, group array into string then cut String length, this is not a good idea.
$a = array("item1","item2","item3" ... "item30");//'item' would be change to any other words.
foreach($a as $b){
$c.=$b.'|';
}
function limitString($string, $limit = 200) {
if(strlen($string) < $limit) {return $string;}
$regex = "/(.{1,$limit})\b/";
preg_match($regex, $string, $matches);
return $matches[1];
}
$d = explode('|',limitString($c));
foreach($d as $e){
echo '<li><a href="">'.$e.'</li>';
}
for example, if the 200th character in item20, it should be broken in item19, output 19 menu lists in this foreach.
You could use substr() as other comments say. To preserve words split, have look at this thread.
Anyway, there's a better way to play with string physical length, but it involves JavaScript.
All you have to do is to create invisible div containing string you want to measure, and then getting it's width and height. Why would you do that? Of course because each letter has different width, also various browsers on various OSes display fonts in little bit other way.
Try the following:
$array = array("item1","item2","item3", "item4", "item5", "item6", "item7", "item8", "item9", "item10", "item11", "item12", "item13", "item14", "item15", "item16", "item17", "item18", "item19", "item20", "item21", "item22", "item23", "item24", "item25", "item26", "item27", "item28", "item29", "item30", "item31", "item32", "item33", "item34", "item35", "item36", "item37", "item38", "item39", "item40", "item41", "item42", "item43", "item44", "item45", "item46", "item47", "item48", "item49", "item50", "item51", "item52", "item53", "item54", "item55", "item56", "item57", "item58", "item59", "item60", "item61", "item62", "item63", "item64", "item65", "item66", "item67", "item68", "item69", "item70", "item71", "item72", "item73", "item74", "item75", "item76", "item77", "item78", "item79", "item80", "item81", "item82", "item83", "item84", "item85", "item86", "item87", "item88", "item89", "item90", "item91", "item92", "item93", "item94", "item95", "item96", "item97", "item98", "item99", "item100");
$max = 200;
$length = 0;
$menu_items = array();
foreach($array as $value){
$length += strlen($value);
if($length <= $max){
$menu_items[] = $value;
}else{
break;
}
}
// Outputing the menu:
echo '<ul><li>'. implode('</li><li>', $menu_items) .'</li></ul>';
Online demo.
You can check it at this part:
foreach($a as $b){
if(strlen($c)<200) $c.=$b.'|'; else return;
}
Related
In need of some help - am trying to analyse news articles.
I have a list of positive words and negative words. I am search the article contents for instances of the words a counting the up.
my problem is that the negative word list is a lot long that the positive so all the results a skewed to negative.
I am looking for a way to normalise the results so a positive word is weighted slightly against the negative to even out the fact that is a considerably high chance of finding a negative word. Unfortunately I have no idea where to start.
Appreciate you taking the time to read this.
Below is the code I have so far.
function process_scores($content)
{
$positive_score = 0;
for ($i = 0; $i < count($this->positive_words); $i++) {
if($this->positive_words[$i] != "")
{
$c = substr_count( strtolower($content) , $this->positive_words[$i] );
if($c > 0)
{
$positive_score += $c;
}
}
}
$negative_score = 0;
for ($i = 0; $i < count($this->negative_words); $i++) {
if($this->negative_words[$i] != "")
{
$c = substr_count( strtolower($content) , $this->negative_words[$i] );
if($c > 0)
{
$negative_score += $c;
}
}
}
return ["positive_score" => $positive_score, "negative_score" => $negative_score];
}
So I don't know php, but this seems less like a php question and more of a question of method. Right now when you analyze an article, you assign words as positive or negative based on whether or not they are in your dictionary, but because your dictionaries are of different sizes, you feel like this isn't giving you a fair analysis of the article.
One method you could try is to assign each word in the article a value. If a word does not exist in your dictionary, have the program prompt for manual interpretation of the word through the command line. Then decide whether the word is positive, negative, or neutral, and have the program add that word to the appropriate dictionary. This will be really annoying at first, but English speakers use roughly the same 2000 words for almost all of our conversation, so after a few articles, you will have robust dictionaries and not have to worry about skew because every single word will have been assigned a value.
I would suggest just throwing in a weighting factor to the output. The exact weighting is determined by trial and error. I went ahead and refactored your code since there was some repetition
<?php
class WordScore {
private $negative_words = [];
private $positive_words = [];
private $positive_weight = 1;
private $negative_weight = 1;
public function setScore(float $pos = 1, float $neg = 1) {
$this->negative_weight = $neg;
$this->positive_weight = $pos;
}
public function processScores($content) {
$positive_score = $this->countWords($content, $this->positive_words);
$negative_score = $this->countWords($content, $this->negative_words);
return [
"positive_score" => $positive_score * $this->positive_weight,
"negative_score" => $negative_score * $this->negative_weight
];
}
private function countWords( string $content, array $words, float $weight = 1 ) {
$count = 0;
foreach( $words as $word ) {
$count += substr_count( strtolower($content) , strtolower($word) );
}
return $count;
}
}
working example at http://sandbox.onlinephpfunctions.com/code/19b4ac3c12d35cf253e9fa6049e91508e4797a2e
Pattern search within a string.
for eg.
$string = "111111110000";
FindOut($string);
Function should return 0
function FindOut($str){
$items = str_split($str, 3);
print_r($items);
}
If I understand you correctly, your problem comes down to finding out whether a substring of 3 characters occurs in a string twice without overlapping. This will get you the first occurence's position if it does:
function findPattern($string, $minlen=3) {
$max = strlen($string)-$minlen;
for($i=0;$i<=$max;$i++) {
$pattern = substr($string,$i,$minlen);
if(substr_count($string,$pattern)>1)
return $i;
}
return false;
}
Or am I missing something here?
What you have here can conceptually be solved with a sliding window. For your example, you have a sliding window of size 3.
For each character in the string, you take the substring of the current character and the next two characters as the current pattern. You then slide the window up one position, and check if the remainder of the string has what the current pattern contains. If it does, you return the current index. If not, you repeat.
Example:
1010101101
|-|
So, pattern = 101. Now, we advance the sliding window by one character:
1010101101
|-|
And see if the rest of the string has 101, checking every combination of 3 characters.
Conceptually, this should be all you need to solve this problem.
Edit: I really don't like when people just ask for code, but since this seemed to be an interesting problem, here is my implementation of the above algorithm, which allows for the window size to vary (instead of being fixed at 3, the function is only briefly tested and omits obvious error checking):
function findPattern( $str, $window_size = 3) {
// Start the index at 0 (beginning of the string)
$i = 0;
// while( (the current pattern in the window) is not empty / false)
while( ($current_pattern = substr( $str, $i, $window_size)) != false) {
$possible_matches = array();
// Get the combination of all possible matches from the remainder of the string
for( $j = 0; $j < $window_size; $j++) {
$possible_matches = array_merge( $possible_matches, str_split( substr( $str, $i + 1 + $j), $window_size));
}
// If the current pattern is in the possible matches, we found a duplicate, return the index of the first occurrence
if( in_array( $current_pattern, $possible_matches)) {
return $i;
}
// Otherwise, increment $i and grab a new window
$i++;
}
// No duplicates were found, return -1
return -1;
}
It should be noted that this certainly isn't the most efficient algorithm or implementation, but it should help clarify the problem and give a straightforward example on how to solve it.
Looks like you more want to use a sub-string function to walk along and check every three characters and not just break it into 3
function fp($s, $len = 3){
$max = strlen($s) - $len; //borrowed from lafor as it was a terrible oversight by me
$parts = array();
for($i=0; $i < $max; $i++){
$three = substr($s, $i, $len);
if(array_key_exists("$three",$parts)){
return $parts["$three"];
//if we've already seen it before then this is the first duplicate, we can return it
}
else{
$parts["$three"] = i; //save the index of the starting position.
}
}
return false; //if we get this far then we didn't find any duplicate strings
}
Based on the str_split documentation, calling str_split on "1010101101" will result in:
Array(
[0] => 101
[1] => 010
[2] => 110
[3] => 1
}
None of these will match each other.
You need to look at each 3-long slice of the string (starting at index 0, then index 1, and so on).
I suggest looking at substr, which you can use like this:
substr($input_string, $index, $length)
And it will get you the section of $input_string starting at $index of length $length.
quick and dirty implementation of such pattern search:
function findPattern($string){
$matches = 0;
$substrStart = 0;
while($matches < 2 && $substrStart+ 3 < strlen($string) && $pattern = substr($string, $substrStart++, 3)){
$matches = substr_count($string,$pattern);
}
if($matches < 2){
return null;
}
return $substrStart-1;
I'm trying to generate strings in PHP with a group of valid characters, cycling through them and appending an extra character on the end of the string, until maximum length is reached. For example, desired output:
a,b,c,d,e,f,aa,ab,ac,ad,ae,af,ba,bb,bc,bd,be,bf,ca,cb..etc
This is my PHP function so far:
<?php
$chars = Array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','X','Y','Z',
'1','2','3','4','5','6','7','8','9','0');
$maxlen = 10;
$input = $chars[0];
while (1):
echo buildInput($maxlen, $chars, $input) . "\n";
endwhile;
function buildInput($maxlen, $chars, $previous)
{
if (array_search(substr($previous, -1), $chars) == sizeof($chars) - 1):
// end of input cycle reached, add another character
$previous = $previous . $chars[0];
endif;
if (strlen($previous) > $maxlen):
die('Max length reached');
endif;
// Remove last character, and append incremented char
$input = substr($previous, 0, -1);
$input = $input . $chars[array_search(substr($previous, -1), $chars)+1];
return $input;
}
?>
It only increments the last character of the string which gets to 0, then appends 'a' and starts over but without trying all the other possible permutations.
Could someone help me with a better method?
Is this the kind of thing you want?
<?php
$chars = array('a','b','c');
$max_length = 3;
function build($base_arr, $ctr) {
global $chars;
global $max_length;
$combos = array();
foreach ($base_arr as $base) {
foreach ($chars as $char) {
echo $base, $char, '<br />';
$combos[] = $base.$char;
}
}
if ($ctr < $max_length) {
build($combos, $ctr + 1);
}
}
foreach ($chars as $char) {
echo $char, '<br />';
}
build($chars, 2);
?>
It'll give you: a, b, c, aa, ab, ac, ba, bb, bc, ca, cb, cc, ..., bcc, caa, cab, cac, cba, cbb, cbc, cca, ccb, ccc.
Your array is so large, though, that using this method on it would take up way too much memory to work. Out of 62 characters (A-Z, a-z, 0-9), the number of possible 10-character permutations is 8.4 x 10^17; so hopefully, you'll be able to find a more efficient method or figure out a way to get the result you want without having to cycle through such a large array. I hope you find what you're looking for!
If you limit yourself to 0-9,a-z (only lower case), then you could use base_convert for this and do it in one line:
for($i = 0; $i < 1000; $i++) echo base_convert($i, 10, 36) . '<br/>';
Here's a demo.
This will print 200 letters: a,b,c,d,...,aa,...,cq
The buildString function will build our string from the least significant number (right) to the most significant (left). By performing a modulus division, you will find the array position of the next character. Add this character to the front of your string, and divide
your number by the size of your array (which is the base number in your character based number system), ignoring the rest.
To explain the method using our normal 10-based number system and the input of 123, you would simply pick the last digit, 3, divide the input by 10, pick the last digit 2, divide the input by 10, pick the last digit 1, divide the input by 10. The input is now 0 and your output is ready...
$chars = array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q'
,'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J'
,'K','L','M','N','O','P','Q','R','S','T','U','V','X','Y','Z','1','2','3','4'
,'5','6','7','8','9','0');
$numChars = count($chars);
// Output numbers from 1 to 200 (a to cq)
for($i = 1; $i <= 200; $i++) {
echo buildString($i).'<br>';
}
// Will also work fine for large numbers - output "dxSA"
echo buildString(1000000).'<br>';
function buildString($int) {
global $chars;
global $numChars;
$output = '';
while($int) {
$output = $chars[($int-1) % $numChars] . $output;
$int = floor(($int-1) / $numChars);
}
return $output;
}
If you have access to gmp extension and PHP 5.3.2+ this will work for the charset you specified:
$result = strtr(
gmp_strval(gmp_init($i, 10), 62),
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
);
For an ecommerce site I want to generate a random coupon code that looks better than a randomly generated value. It should be a readable coupon code, all in uppercase with no special characters, only letters (A-Z) and numbers (0-9).
Since people might be reading this out / printing it elsewhere, we need to make this a simple-to-communicate value as well, perhaps 8-10 characters long.
Something like perhaps,
AHS3DJ6BW
B83JS1HSK
(I typed that, so it's not really that random)
$chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$res = "";
for ($i = 0; $i < 10; $i++) {
$res .= $chars[mt_rand(0, strlen($chars)-1)];
}
You can optimize this by preallocating the $res string and caching the result of strlen($chars)-1. This is left as an exercise to the reader, since probably you won't be generating thousands of coupons per second.
Try this:
substr(base_convert(sha1(uniqid(mt_rand())), 16, 36), 0, 10)
Why don't keep it simple?
<?php
echo strtoupper(uniqid());
?>
Always returns 13 character long uppercased random code.
You can use the coupon code generator PHP class file to generate N number of coupons and its customizable, with various options of adding own mask with own prefix and suffix. Simple PHP coupon code generator
Example:
coupon::generate(8); // J5BST6NQ
http://webarto.com/35/php-random-string-generator
Here you go.
function randr($j = 8){
$string = "";
for($i=0;$i < $j;$i++){
srand((double)microtime()*1234567);
$x = mt_rand(0,2);
switch($x){
case 0:$string.= chr(mt_rand(97,122));break;
case 1:$string.= chr(mt_rand(65,90));break;
case 2:$string.= chr(mt_rand(48,57));break;
}
}
return strtoupper($string); //to uppercase
}
If there are no security requirements for these, then you don't really need randomly generated codes. I would just use incremental IDs, such as those generated by whatever RDBMS you use. Optionally, if you have different types of coupons, you could prefix the codes with something, e.g.:
CX00019 QZ0001C
CX0001A QZ0001D
CX0001B QZ0001E
Alternately, you could even use dictionary words in the coupon, as such coupon codes are easier to remember and faster for users to type. Companies like Dreamhost use these for their promo codes, e.g.:
Promo60
NoSetupFee
YELLOWGORILLA82
Some of these are obviously human-created (which you might want to have the option of), but they can also be generated using a dictionary list. But even if they are randomly-generated nonsense phrases, the fact that the characters follow a logical pattern still makes it much more user-friendly than something like R7QZ8A92F1. So I would strongly advise against using the latter type of coupon codes just on the basis that they "look cool". Your customers will thank you.
$size = 12;
$string = strtoupper(substr(md5(time().rand(10000,99999)), 0, $size));
function generateCouponCode($length = 8) {
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$ret = '';
for($i = 0; $i < $length; ++$i) {
$random = str_shuffle($chars);
$ret .= $random[0];
}
return $ret;
}
you can find a lot of function in php rand manual
http://php.net/manual/en/function.rand.php
i like this one
<?php
//To Pull 8 Unique Random Values Out Of AlphaNumeric
//removed number 0, capital o, number 1 and small L
//Total: keys = 32, elements = 33
$characters = array(
"A","B","C","D","E","F","G","H","J","K","L","M",
"N","P","Q","R","S","T","U","V","W","X","Y","Z",
"1","2","3","4","5","6","7","8","9");
//make an "empty container" or array for our keys
$keys = array();
//first count of $keys is empty so "1", remaining count is 1-7 = total 8 times
while(count($keys) < 8) {
//"0" because we use this to FIND ARRAY KEYS which has a 0 value
//"-1" because were only concerned of number of keys which is 32 not 33
//count($characters) = 33
$x = mt_rand(0, count($characters)-1);
if(!in_array($x, $keys)) {
$keys[] = $x;
}
}
foreach($keys as $key){
$random_chars .= $characters[$key];
}
echo $random_chars;
?>
$length = 9;
$code = (strtoupper(substr(md5(time()), 0, $length)));
Just Write
$voucher_no = date('ymd') . rand(1000, 9999);
while(SapItem::where('voucher_no', $voucher_no)->exists()){
$voucher_no = date('ymd') . rand(1000, 9999);
}
Output: 2204171447
I'm starting to work on a small script that takes a string, counts the number of characters, then, based on the number of characters, splits/breaks the string apart and sends/emails 110 characters at a time.
What would be the proper logic/PHP to use to:
1) Count the number of characters in the string
2) Preface each message with (1/3) (2/3) (3/3), etc...
3) And only send 110 characters at a time.
I know I'd probably have to use strlen to count the characters, and some type of loop to loop through, but I'm not quite sure how to go about it.
Thanks!
You could use str_split, if you're not concerned with where you break the strings.
Else, if you are concerned with this (and want to, say, split only on a whitespace), you could do something like:
// $str is the string you want to chop up.
$split = preg_split('/(.{0,110})\s/',
$str,
0,
PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
With this array you could then simply do:
$count = count($split);
foreach ($split as $key => $message) {
$part = sprintf("(%d/%d) %s", $key+1, $count, $message);
// $part is now one of your messages;
// do what you wish with it here.
}
use str_split() and iterate over the resulting array.
From the top of my head, should work as is, but doesn't have to. Logic is ok though.
foreach ($messages as $msg) {
$len = strlen($msg);
if ($len > 110) {
$parts = ceil($len / 100);
for ($i = 1; $i <= $parts; $i++) {
$part = $i . '/' . $parts . ' ' . substr($msg, 0, 110);
$msg = substr($msg, 109);
your_sending_func($part);
}
} else {
your_sending_func($msg);
}
}