Good evening
I created a while adding spaces in a variable . it's exactly what I need, but now I need to centralize the text between the spaces:
here is the code in PHP:
$psn = "ABCDEFGH";
$psnSize = strlen($psn);
while($psnSize <= 20)
{
$psn = $psn." ";
$psnSize++;
}
The max size is 20 characters, and I need all psn's have the same size (20 characters)
I'm getting the result but the spaces are added to the end of the text and now I want to distribute the spaces between the text to get it centralized.
Thank you so much.
You can use all native functions to achieve this:
function createLRPadding($str, $chars = 20)
{
# Count the length
$strlen = strlen($str);
# Don't do anything if you are at the max characters
if($strlen >= $chars)
return $str;
# Get left and right balance
$len = ($chars - $strlen) / 2;
# Create fills on the left and right of the string and implode them to make one string
return implode('', array_fill(0,round($len, 0, PHP_ROUND_HALF_UP),' ')).$str.implode('', array_fill(0,round($len, 0, PHP_ROUND_HALF_DOWN),' '));
}
To use:
echo createLRPadding('Cool string');
To adjust the padding, add a second parameter:
echo createLRPadding('Cool string', 40);
The first example (default 20 pad) will write:
Cool string
Related
I want to trim a given text at a given number of pixels.
To achieve this, I loop through the length of the text and with each loop, I add the next character and measure the string with the help of the method imagettfbbox. - This works fine for me on "normal text's" e.g. like this posting. ;)
But if I add some emoji's to my text, the length is even shorter than expected. I think this is because emojis encoded with more than 1 byte. -
That's why, I'm using mb_strwidth and mb_substr.
The method imagettfbbox expects a font-file to measure the given string. This font is able to display my emoji's.
Here's my code
$Line = "🏡 Garden, 🕓 Clock, some other things";
$MaxLength = 100; // Pixel
// Start looping through the line, start with 15 characters
for ( $Len = 15; $Len < mb_strwidth($Line); $Len++ ) {
// Grep x Chars from line
$NewLine = mb_substr($Line, 0, $Len);
// Measure string
$FontBox = imagettfbbox(12, 0, "fonts/OpenSansEmoji.ttf", $NewLine);
$TextWidth = $FontBox[2];
// Compare measured string with given max length
if ( $TextWidth > $MaxLength ) {
$Line = mb_substr($Line, 0, $Len - 2) . "...";
break;
}
}
$Line = NewLine;
Expample lines
"🏡 Garden, 🕓 Clock, some other things"
"🏡🏡🏡🏡🏡🏡🏡🏡🏡🏡🏡🏡🏡🏡🏡🏡 Gaaaaaaaaaaaardeeeeeeeeeeeeeeeeeen"
"mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm"
"iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"
"erufgbwuiergbvfuipwervbpiuwebvruiwbevuibwüeriuvbwieuörvböwieuvbr"
Result
As you can see, the more emoji's i use, the shorter the line.
Kind regards from a non native speaker. :)
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.
I am using a terrible wrapper of PDFLib that doesn't handle the problem PDFLib has with cells that are more than the character limit (Which is around 1600 characters per cell).
So I need to break a large paragraph into smaller strings that fit neatly into the cells, without breaking up words, and as close to the end of the line as possible.
I am completely stumped about how to do this efficiently (I need it to run in a reasonable amount of time)
Here is my code, which cuts the block up into substrings based on character length alone, ignoring the word and line requirements I stated above:
SPE_* functions are static functions from the wrapper class,
SetNextCellStyle calls are used to draw a box around the outline of the cells
BeginRow is required to start a row of text.
EndRow is required to end a row of text, it must be called after BeginRow, and if the preset number of columns is not completely filled, an error is generated.
AddCell adds the string to the second parameter number of columns.
function SPE_divideText($string,$cols,$indent,$showBorders=false)
{
$strLim = 1500;
$index = 0;
$maxIndex = round((strlen($string) / 1500-.5));
$retArr= array();
while(substr($string, $strLim -1500,$strLim)!=FALSE)
{
$retArr[$index] = substr($string, $strLim -1500,$strLim);
$strLim+=1500;
SPE_BeginRow();
SPE_SetNextCellStyle('cell-padding', '0');
if($indent>0)
{
SPE_Empty($indent);
}
if($showBorders)
{
SPE_SetNextCellStyle('border-left','1.5');
SPE_SetNextCellStyle('border-right','1.5');
if($index == 0)
{
SPE_SetNextCellStyle('border-top','1.5');
}
if($index== $maxIndex)
{
SPE_SetNextCellStyle('border-bottom','1.5');
}
}
SPE_AddCell($retArr[$index],$cols-$indent);
SPE_EndRow();
$index++;
}
}
Thanks in advance for any help!
Something like this should work.
function substr_at_word_boundary($string, $chars = 100)
{
preg_match('/^.{0,' . $chars. '}(?:.*?)\b/iu', $string, $matches);
$new_string = $matches[0];
return ($new_string === $string) ? $string : $new_string;
}
$string = substr_at_word_boundary($string, 1600)
If I have sentences like this:
$msg = "hello how are you?are you fine?thanks.."
and I wish to seperate it into 3 (or whatever number).
So I'm doing this:
$msglen = strlen($msg);
$seperate = ($msglen /3);
$a = 0;
for($i=0;$i<3;$i++)
{
$seperate = substr($msg,$a,$seperate)
$a = $a + $seperate;
}
So the output should be..
hello how are
[a space here->] you?are you [<-a space here]
fine?thanks..
So is it possible to separate at middle of any word instead of having a space in front or end of the separated message?
Such as "thank you" -> "than" and "k you" instead of "thank" " you ".
Because I'm doing a convert function and with a space in front or end it will effect the convertion , and the space is needed for the conversion,so I can't ignore or delete it.
Thanks.
I take it you can't use trim because the message formed by the joined up strings must be unchanged?
That could get complicated. You could make something that tests for a space after the split, and if a space is detected, makes the split one character earlier. Fairly easy, but what if you have two spaces together? Or a single lettered word? You can of course recursively test this way, but then you may end up with split strings of lengths that are very different from each other.
You need to properly define the constraints you want this to function within.
Please state exactly what you want to do - do you want each section to be equal? Is the splitting in between words of a higher priority than this, so that the lengths do not matter much?
EDIT:
Then, if you aren't worried about the length, you could do something like this [starting with Eriks code and proceeding to change the lengths by moving around the spaces:
$msg = "hello how are you?are you fine?thanks..";
$parts = split_without_spaces ($msg, 3);
function split_without_spaces ($msg, $parts) {
$parts = str_split(trim($msg), ceil(strlen($msg)/$parts));
/* Used trim above to make sure that there are no spaces at the start
and end of the message, we can't do anything about those spaces */
// Looping to (count($parts) - 1) becaause the last part will not need manipulation
for ($i = 0; $i < (count($parts) - 1) ; $i++ ) {
$k = $i + 1;
// Checking the last character of the split part and the first of the next part for a space
if (substr($parts[$i], -1) == ' ' || $parts[$k][0] == ' ') {
// If we move characters from the first part to the next:
$num1 = 1;
$len1 = strlen($parts[$i]);
// Searching for the last two consecutive non-space characters
while ($parts[$i][$len1 - $num1] == ' ' || $parts[$i][$len1 - $num1 - 1] == ' ') {
$num1++;
if ($len1 - $num1 - 2 < 0) return false;
}
// If we move characters from the next part to the first:
$num2 = 1;
$len2 = strlen($parts[$k]);
// Searching for the first two consecutive non-space characters
while ($parts[$k][$num2 - 1] == ' ' || $parts[$k][$num2] == ' ') {
$num2++;
if ($num2 >= $len2 - 1) return false;
}
// Compare to see what we can do to move the lowest no of characters
if ($num1 > $num2) {
$parts[$i] .= substr($parts[$k], 0, $num2);
$parts[$k] = substr($parts[$k], -1 * ($len2 - $num2));
}
else {
$parts[$k] = substr($parts[$i], -1 * ($num1)) . $parts[$k];
$parts[$i] = substr($parts[$i], 0, $len1 - $num1);
}
}
}
return ($parts);
}
This takes care of multiple spaces and single lettered characters - however if they exist, the lengths of the parts may be very uneven. It could get messed up in extreme cases - if you have a string made up on mainly spaces, it could return one part as being empty, or return false if it can't manage the split at all. Please test it out thoroughly.
EDIT2:
By the way, it'd be far better for you to change your approach in some way :) I seriously doubt you'd actually have to use a function like this in practice. Well.. I hope you do actually have a solid reason to, it was somewhat fun coming up with it.
If you simply want to eliminate leading and trailing spaces, consider trim to be used on each result of your split.
If you want to split the string into exact thirds it is not known where the cut will be, maybe in a word, maybe between words.
Your code can be simplified to:
$msg = "hello how are you?are you fine?thanks..";
$parts = str_split($msg, ceil(strlen($msg)/3));
Note that ceil() is needed, otherwise you might get 4 elements out because of rounding.
You're probably looking for str_split, chunk_split or wordwrap.
I have a PHP loop that adds data into a table cell. However, I want to apply a static size to the table cell, so if more data is returned than can fit inside the cell I want the excess characters to be cut off and end with a "..."
For example, one data entry has 270 characters, but only the first 100 are displayed in the table cell. Follow by a "..."
Any ideas on how to do this?
Thanks!
if (strlen($str) > 100) $str = substr($str, 0, 100) . "...";
You can use mb_strimwidth
printf('<td>%s</td>', mb_strimwidth($cellContent, 0, 100, '…'));
If you want to truncate with respect to word boundaries, see
Truncate a multibyte String to n chars
You can also control content display with the CSS property text-overflow: ellipsis
http://www.quirksmode.org/css/textoverflow.html
Unfortunately, browser support varies.
function print_dots($message, $length = 100) {
if(strlen($message) >= $length + 3) {
$message = substr($message, 0, $length) . '...';
}
echo $message;
}
print_dots($long_text);
$table_cell_data = ""; // This would hold the data in the cell
$cell_limit = 100; // This would be the limit of characters you wanted
// Check if table cell data is greater than the limit
if(strlen($table_cell_data) > $cell_limit) {
// this is to keep the character limit to 100 instead of 103. OPTIONAL
$sub_string = $cell_limit - 3;
// Take the sub string and append the ...
$table_cell_data = substr($table_cell_data,0,$sub_string)."...";
}
// Testing output
echo $table_cell_data."<br />\n";