Problem running str_pad in PHP

Asked

Viewed 881 times

1

I studied the PHP function called str_pad. I happen to be able to make it work well in most cases, but.... when I put as a character to be filled, a white space " ", it occurs that simply do not appear the spaces, neither right, nor left, and neither starting from the Center also.

In the browser only appears a single white character, the others are ignored for viewing, existing only in the source code, by the Inspector.

You see, I’ve tried the &nbsp, I tried the keyboard, the codes: alt+0160, but I could not. PS: with the alt + 0160 in place of a space, even appears some spaces on the screen, but also appears a strange signal that is " ". The code is very simple, see:

<?php

    $nome= "Island Avenue";
    $novo= str_pad($nome,30," ",STR_PAD_BOTH);

    print("Minha nova casa, localizada na $novo é linda!");

?>
  • I tested it on ideone.com and it worked. It’s saving with utf-8 encoding?

  • Marcos Xavier, I’m using Notepad++, and yes, I’ve saved with the UTF-8 NO GOOD option. But I can’t see the blanks, only one and the others are suppressed in the view. PS: using str_replace() indicated by Isac, beauty, but would like to solve only with str_pad().

2 answers

1


has to do with coding and does not affect the problem of str_pad. You can fix it by setting the encoding utf-8 which would be the most appropriate or even using the special encoding for that letter o &eacute;.

In relation to str_pad remember that in html multiple blank spaces are ignored, that’s why you don’t see the str_pad functioning properly.

If you change the letter of str_pad by any other letter, for example a !, see how it looks:

inserir a descrição da imagem aqui

To solve the space problem you can apply a substitution to &nbsp; immediately after the str_pad:

<?php
    $nome = "Island Avenue";
    $novo = str_pad($nome,30," ",STR_PAD_BOTH);
    $novo = str_replace(" ", "&nbsp;",$novo); //aqui substitui os espaços por nbsp's

    print("Minha nova casa, localizada na $novo &eacute; linda!");
?>

And it already works as expected:

inserir a descrição da imagem aqui

You can even combine the two functions by doing directly:

$nome = "Island Avenue";
$novo = str_replace(" ", "&nbsp;",str_pad($nome,30," ",STR_PAD_BOTH));
  • Isac, honestly, it was amazing your help, in a simple way, using str_replace with [&nbsp;] Now, two questions: 1) the [&nbsp] can be without the character ";", right? Even I tested and worked, without the ";". 2) You suggested using str_replace() after str_pad(), blz, but you tested the [&nbsp;] straight on str_pad so you didn’t need another (str_replace) function?? grateful!

  • @Fernandes Sem o ; is incorrect as all special html characters need the ;, now it may work depending on the browser realizing what it was trying to do. str_pad directly with &nbsp; does not work because it will put the 6 characters as pad. Remember that the idea of pad is a character applied several times. In text &nbsp; are 6. But you can combine the two with str_replace(" ", "&nbsp;",str_pad($nome,30," ",STR_PAD_BOTH));

  • Vlw Isac, after a lot of searching and listening to some of the placements here, I really think the best output is to use str_replace() after str_pad(). Only one line and one more function, since this, str_replace(), accepts multi-byte, while str_pad() does not accept. Grateful.

1

The str_pad does not work with multi-byte characters, since it does not add all characters at once.

The original code of str_pad is exactly:

switch (pad_type_val) {
    case STR_PAD_RIGHT:
        left_pad = 0;
        right_pad = num_pad_chars;
        break;

    case STR_PAD_LEFT:
        left_pad = num_pad_chars;
        right_pad = 0;
        break;

    case STR_PAD_BOTH:
        left_pad = num_pad_chars / 2;
        right_pad = num_pad_chars - left_pad;
        break;
}

/* First we pad on the left. */
for (i = 0; i < left_pad; i++)
    ZSTR_VAL(result)[ZSTR_LEN(result)++] = pad_str[i % pad_str_len];

/* Then we copy the input string. */
memcpy(ZSTR_VAL(result) + ZSTR_LEN(result), ZSTR_VAL(input), ZSTR_LEN(input));
ZSTR_LEN(result) += ZSTR_LEN(input);

/* Finally, we pad on the right. */
for (i = 0; i < right_pad; i++)
    ZSTR_VAL(result)[ZSTR_LEN(result)++] = pad_str[i % pad_str_len];

ZSTR_VAL(result)[ZSTR_LEN(result)] = '\0';

RETURN_NEW_STR(result);

Source.

Note the presence of i % pad_str_len, ie it just adds a single byte, which can make an unknown byte remain. For example, if you are using the chr(160), This is for Latin1 and not for UTF8.

In Latin1, the byte A0 represents "non-breaking space". But the same thing in UTF8 requires two bytes, being them C2 A0. If you cut one of them, for example, isolating C2, you will have a ?.


If you want a "new version" of str_pad we could create a mb_str_pad():

const STR_PAD_INSERT_ALL = 4;

function mb_str_pad(string $input, int $pad_length, string $pad_string, int $pad_type, string $pad_encoding = 'utf8') : string {

    $result = '';
    $pad_insert_all = 0;
    $pad_inset_limit = 1;
    $pad_str_len = mb_strlen($pad_string, $pad_encoding);
    $input_len = mb_strlen($input, $pad_encoding);

    if ($pad_length < 0 || $pad_length <= $input_len) {
        return $input;
    }
    
    if(($pad_type & STR_PAD_INSERT_ALL) === STR_PAD_INSERT_ALL){
        $pad_insert_all = PHP_INT_MAX;
        $pad_inset_limit = null;
        $pad_type -= STR_PAD_INSERT_ALL;
    }

    if ($pad_str_len === 0) {
        trigger_error ( "Padding string cannot be empty", E_WARNING);
        return $input;
    }

    if ($pad_type < STR_PAD_LEFT || $pad_type > STR_PAD_BOTH) {
        trigger_error ("Padding type has to be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH", E_WARNING);
        return $input;
    }

    $num_pad_chars = $pad_length - $input_len;
    if ($num_pad_chars >= PHP_INT_MAX) {
        trigger_error ("Padding length is too long", E_WARNING);
        return $input;
    }

    switch ($pad_type) {
        case STR_PAD_RIGHT:
            $left_pad = 0;
            $right_pad = $num_pad_chars;
            break;

        case STR_PAD_LEFT:
            $left_pad = $num_pad_chars;
            $right_pad = 0;
            break;

        case STR_PAD_BOTH:
            $left_pad = floor($num_pad_chars / 2);
            $right_pad = $num_pad_chars - $left_pad;
            break;
    }

    for ($i = 0; $i < $left_pad; $i++){
        $result .= mb_substr($pad_string, ($i % $pad_str_len) &~$pad_insert_all, $pad_inset_limit, $pad_encoding);
    }

    $result .= $input;

    for ($i = 0; $i < $right_pad; $i++){
        $result .= mb_substr($pad_string, ($i % $pad_str_len) &~$pad_insert_all, $pad_inset_limit, $pad_encoding);
    }

    return $result;
}

This requires PHP 7+

This is an extremely version based on the original version of PHP, indicated above, with some changes:

It supports multi-bytes, so you can do:

mb_str_pad($nome, 30, "\xc2\xa0", STR_PAD_BOTH, 'utf8');

Differences from the original version:

PS: Assuming I have not entered any bug.

  • Support for multi-bytes:

    It supports characters that require multiple bytes. You can specify the type of encoding used, including UTF8, which is the default.

  • A new "STR_PAD_INSERT_ALL":

    You can insert the entire string, instead of "switching to each other", if you have a string with more than one character (example: "abc"), you can specify to always insert "abc", this has a side effect since the number of inserted characters is not measured. To use, just use STR_PAD_BOTH | STR_PAD_INSERT_ALL, but that’s not necessary in your case.

  • Return in case of error:

    Even if a WARNING is issued it will return the original string, which is not the behavior of the original function.


  • Inkeliz, grateful for the explanation, but I confess that, for the little experience with php, I understood almost nothing (rs). But what really worked was the Isac tip, that is, using str_pad(), and then a str_replace() to take the blanks that were hidden, to make them visible, replicating them by "&nbsp;" That is, str_replace() accepts multi-byte character (&nbsp;) but str_pad() does not. That’s what I got. And using str_replace() after str_pad() is much more practical than creating a function like mb_str_pad() just for that.

  • The str_replace replaces one value with another, it accepts "any value". The set of str_pad + str_replace has side effects. For example, in its string "Island Avenue" has been replaced by "Island&nbsp;Avenue", that is even the space between them has been replaced, this does not occur in my function. It is not only "practicality", this function (which I named mb_str_pad) has the "same" behavior of the native PHP function, with the addition of multi-byte character support.

  • Inkeliz, you see, looking at its function, it’s relatively long, okay? I know it must have a security charge and maybe, after all, you made it thinking about the side effects, but... in my case, I just want to fill and VISUALIZE, the blank spaces, I think that this "side effect" that you mentioned is not really a bug, or enough? And if this is the case, it would not be better to create a function [very short] that would take the text to be filled with spaces and (continue...)

  • and use: a str_pad(), then str_replace() only that str_replace() would be invoked twice: 1a. until the beginning of the first character != from " or "&nbsp;", and after the last (say) valid character, to the length of the string with hidden spaces, to then join the two pieces of the original string, and form the string that goes to the result? that is, str_replace() would not take whitespace inside the source string, ok?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.