http://www.republicof3.com/how-to-generate-unique-promotion-discount-codes-in-php/
I have found a function to generate unique promotion code in PHP
But there is a big problem, if the number of codes to be generated more then the number of remain combination(all combination-length of exclude_codes_array), the function will become infinite loop.
For example: If the $characters = "0A"; the combination are "00", "0A", "A0", "AA" = 4, if the $no_of_codes >4, the loop is cannot stopped.
So I want to check the the number of codes and all remaining combination of codes before the loop, how to calculate the combination of a string?
As per what you have calculated for A0.
AA, 00 , A0, 0A
Generalizing and using basic permutation and combination it should be ,
2^{strlen($str)};
Discrete Math
available chars = 2 ("A", "0")
available spaces = 2 ("**")
chasr^spaces = 4
available chars = 2 ("A", "0")
available spaces = 3 ("***")
chars^spaces = 8
available chars = 3 ("A", "B", "0")
available spaces = 2 ("**")
chars^spaces = 9
Related
I have a PHP problem.
I need to write a number from a sets of digits 0-9. Each set has 10 digits, each digit once.
I need to count the number of sets that I have to use to write the number.
For example number 10 is written from one set, but number 300 uses 2 sets because it has two zeros.
But, the problem is that 6 and 9 are considered the same. They can be rotated by 180 degrees.
Number 266 will be using one set, 369 also is using one set, but 5666 is using 2 sets.
I would be very grateful if you could somehow help me.
Here is how I have started and stuck up, have no more clue how to loop through it. Tried many things, nothing successful.
<?php
function countSet($num) {
$array = str_split($num);
$statarr = [0,1,2,3,4,5,6,7,8,9];
$a1 = $array; $a2 = $statarr;
$result = array_intersect($a1,$a2);
$count = array_count_values($result); }
?>
If you just need to know how many sets you need for a number, you can solve by counting the numbers. For the case of the 9, just replace every 9 by a 6 and divide the number of 6 by two. Something like this (sorry if there's any syntax error, I'm on mobile):
function countSet($input) {
// Convert the input into a string and replace every 9 by a 6. Then convert it to array
$numbers = str_split(str_replace("9", "6", strval($input)));
// Count occurrences for each number
$usedNumbers = array_count_values($numbers);
// If we have a 6, must divide it by 2 (6 represents 6 and 9
if (array_key_exists("6", $usedNumbers)) {
$usedNumbers["6"] = ceil($usedNumbers["6"] / 2);
}
// Now we just need to know the max number of occurrences for a single number as our result.
return max($usedNumbers);
}
See an online demo here
I am looking for a solution for a smart number formatting in PHP.
For example we have 2 numbers below and we need 4 digits after decimal:
1.12345678
0.00002345678
Using normal number formatting, here are the results:
1.1234 // Looking good
0.0000 // No good
Can we make it keep going until there are 4 non-zero digits? If it can return 0.00002345, perfect!!!
Many thanks!!!
Might be overkill and the pattern could be optimized, but for fun; get optional 0s AND 4 NOT 0s after the .:
preg_match('/\d+\.([0]+)?[^0]{4}/', $num, $match);
echo $match[0];
To round it we can get 5 digits after the 0s and then format it to the length of that -1 (which will round):
preg_match('/\d+\.([0]+?[^0]{5})/', $num, $match);
echo number_format($match[0], strlen($match[1])-1);
For $num = '1234.000023456777'; the result will be 1,234.00002346 and the $matches will contain:
Array
(
[0] => 1234.000023456
[1] => 000023456
)
So this is the code I made to slove this:
$num = 0.00002345678;
$num_as_string = number_format($num,PHP_FLOAT_DIG,'.','');
$zeros = strspn($num_as_string, "0", strpos($num_as_string, ".")+1);
echo number_format($num, (4+$zeros), '.', '');
It converts the float number to a string, checks how many zeros exist after the decimal point and then does a number format with the extra zeros accounted for.
Note that it may break if your float is too big, you can change PHP_FLOAT_DIG to a number larger that may fix that.
I'm generating a unique 5 digit code using the following.
$randomUniqueNumber = rand(10000,99999);
I need to change this to an alphanumeric number with 5 digits and 2 letters.
The below gives me an alphanumeric number, but not restricted to just 2 letters.
$generated = substr(md5(rand()),0,5);
How would I generate a random string with 5 digits, and two letters?
There are probably a few ways to do it, but the following is verbose to get you going.
<?php
// define your set
$nums = range(0, 9);
$alphas = range('a', 'z');
// shuffle sets
shuffle($nums);
shuffle($alphas);
// pick out only what you need
$nums = array_slice($nums, 0, 5);
$alphas = array_slice($alphas, 0, 2);
// merge them together
$set = array_merge($nums, $alphas);
// shuffle
shuffle($set);
// create your result
echo implode($set); //86m709g
https://3v4l.org/CV7fS
Edit:
After reading I'm generating a unique 5 digit code using the following. I suggest, instead, create your string by changing the base from an incremented value, rather than random (or shuffled) as you will undoubtedly get duplicates, and to achieve no dupes you would need to pre-generate and store your entire set of codes and pick from them.
Instead look at something like hashids.
I am working in php and I am trying to create 1000 tickets in a database. Each ticket needs it's own unique code that consists of letters and numbers about 6 characters long.
EXP.
Tbl_Tickets
ID code
1 3F2jk7
2 2HGUF1
3 9FJDNJ
4 MFJEY9
5 23988D
I was wondering is there a simple way of doing this with php, or excel, or any other way for that matter. I know that i can use a random number generator, but the check for the Unique would have a large BigO notation and the check would get messy.
Unique is not compatible with random, but the following might suit:
=CHOOSE(RANDBETWEEN(1,2),RANDBETWEEN(0,9),CHAR(RANDBETWEEN(65,90)))
copied across to populate six columns (say A to F) with, in G:
=A1&B1&C1&D1&E1&F1
and both copied down to say row 1100. Then select G, copy Paste Special Values, and Remove Duplicates on ColumnG and select first 1000 entries.
You could easily create an array of strings in php and write it to a database:
function generateRandomString($length = 6, $letters = '1234567890QWERTYUIOPASDFGHJKLZXCVBNM'){
$s = '';
$lettersLength = strlen($letters)-1;
for($i = 0 ; $i < $length ; $i++){
$s .= $letters[rand(0,$lettersLength)];
}
return $s;
}
// Create an array with random strings
for ($i=0; $i<1000; $i++){
$ticket_numbers = array();
$ticket_number = generateRandomString();
while (in_array($ticket_number,$ticket_numbers))
$ticket_number = generateRandomString();
$ticket_numbers[] = $ticket_number;
}
// Write the array to a database
$con = mysqli_connect("myhost","myuser","mypassw","mybd") or die("Error");
foreach ($ticket_numbers as $number){
mysqli_query($con,"Your insert query using the value $number");
}
mysqli_close($con);
This should help you in the right direction though there are probably better ways to do this.
The function generateRandomString() was taken from How to generate random numbers/letters with PHP/Javascript
And another option. Encryption is guaranteed to be unique, so encrypting the numbers 0, 1, 2, ... will give you guaranteed unique random-seeming output. Six characters is 30 bits using Base32, or 36 bits using Base64. You will need a 30 (or 36 bit) cypher. Unless you have a library that includes Hasty Pudding cypher (unlikely) then just implement a simple four round Feistel cypher with the appropriate block size. It will not be completely secure, but it will be enough to defeat casual attacks.
This will produce random strings in column B with no repeats from B1 thru B1001
Sub Lottery()
Dim i As Long, j As Long, c As Collection
Set c = New Collection
v = Split("0,1,2,3,4,5,6,7,8,9,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", ",")
For i = 1 To 5000
can = ""
For j = 1 To 6
can = can & v(Application.RandBetween(0, 35))
Next j
On Error Resume Next
c.Add can, CStr(can)
On Error GoTo 0
If c.Count = 1000 Then Exit For
Next i
For i = 1 To 1000
Cells(i + 1, 2).Value = c(i)
Next i
End Sub
Is there a term for the idea of storing large numbers as letters? For example let's say I have the (relatively small) number 138201162401719 and I want to shrink the number of characters (I know this does not help with saving disk space) to the fewest possible number of characters. There are 26 letters in the English alphabet (but i count them as 25 since we need a zero letter). If I start splitting up my large number into pieces that are each 25 or less I get:
13, 8, 20, 11, 6, 24, 0, 17, 19
If I then count the numbers of the alphabet a=0, b=1, c=2, d=3... I can convert this to:
NIULGYART
So I went from 15 digits long (138201162401719) to 9 characters long (NIULGYART). This could of course be easily converted back to the original number as well.
So...my first question is "Does this have a name" and my second "Does anyone have PHP code that will do the conversion (in both directions)?"
I am looking for proper terminology so that I can do my own research in Google...though working code examples are cool too.
This only possible if you're considering to store your number before processing as a string. Because you can't store huge number as integers. You will lost the precision (13820116240171986468445 will be stored as 1.3820116240172E+22) so the alot of digits are lost.
If you're considering storing the number as a string this will be your answer:
Functions used: intval, chr and preg_match_all.
<?php
$regex = '/(2[0-5])|(1[0-9])|([0-9])/';
$numberString = '138201162401719';
preg_match_all($regex, $numberString, $numberArray, PREG_SET_ORDER);
echo($numberString . " -> ");
foreach($numberArray as $value){
$character = chr (intval($value[0]) + 65);
echo($character);
}
?>
Demo
This is the result:
138201162401719 -> NIULGYART
Here's how I would do it:
Store the big number as a string and split it into an array of numbers containing one digit each
Loop through the array extract 2-digit chunks using substr()
Check if the number is less than 26 (in which case, it is an alphabet) and add them to an array
Use array_map() with chr() to create a new array of characters from the above array
Implode the resulting array to get the cipher
In code:
$str = '138201162401719';
$arr = str_split($str);
$i = 0; // starting from the left
while ($i < count($arr)) {
$n = substr($str, $i, 2);
$firstchar = substr($n, 0, 1);
if ($n < 26 && $firstchar != 0) {
$result[] = substr($str, $i, 2);
$i += 2; // advance two characters
} else {
$result[] = substr($str, $i, 1);
$i++; // advance one character
}
}
$output = array_map(function($n) {
return chr($n+65);
}, $result);
echo implode($output); // => NIULGYART
Demo.
As an alternative, you could convert the input integer to express it in base 26, instead of base 10. Something like (pseudocode):
func convertBase26(num)
if (num < 0)
return "-" & convertBase26(-num) // '&' is concatenate.
else if (num = 0)
return "A"
endif
output = "";
while (num > 0)
output <- ('A' + num MOD 26) & output // Modulus operator.
num <- num DIV 26 // Integer division.
endwhile
return output
endfunc
This uses A = 0, B = 1, up to Z = 25 and standard place notation: 26 = BA. Obviously a base conversion is easily reversible.
strtr() is a magnificent tool for this task! It replaces the longest match as is traverses the string.
Code: (Demo)
function toAlpha ($num) {
return strtr($num, range("A", "Z"));
}
$string = toAlpha("138201162401719");
echo "$string\n";
$string = toAlpha("123456789012345");
echo "$string\n";
$string = toAlpha("101112131415161");
echo "$string\n";
$string = toAlpha("2625242322212019");
echo "$string";
Output:
NIULGYART
MDEFGHIJAMDEF
KLMNOPQB
CGZYXWVUT
Just flip the lookup array to reverse the conversion: https://3v4l.org/YsFZu
Merged: https://3v4l.org/u3NQ5
Of course, I must mention that there is a vulnerability with converting a sequence of letters to numbers and back to letters. Consider BB becomes 11 then is mistaken for eleven which would traslate to L when converted again.
There are ways to mitigate this by adjusting the lookup array, but that may not be necessary/favorable depending on program requirements.
And here is another consideration from CodeReview.
I have been trying to do the same thing in PHP without success.
Assuming I'm using the 26 letters of the English alphabet, starting with A = 0 down to Z as 25:
I find the highest power of 26 lower than the number I am encoding. I divide it by the best power of 26 I found. Of the result I take away the integer, convert it to a letter and multiply the decimals by 26. I keep doing that until I get a whole number. It's ok to get a zero as it's an A, but if it has decimals it must be multiplied.
For 1 billion which is DGEHTYM and it's done in 6 loops obviously. Although my answer demonstrates how to encode, I'm afraid it does not help doing so on PHP which is what I'm trying to do myself. I hope the algorithm helps people out there though.