0

So I am trying to remove line feed within an array but not cariage returns. Having trouble using array walk, the ltrim function is not working.

I need to remove ONLY the line feed("\n") not the cariage return("\r") so using trim will not work. I tried setting the chr(10) and still not working. Any idea's

$array = array(
        [0] => array(C1TEXT => 0001),
        [1] => array(C1TEXT => 0002),
        [2] => array(C1TEXT => \n),
        [3] => array(C1TEXT => \r),
        [4] => array(C1TEXT => 0003),
        [5] => array(C1TEXT => 0004),
        [6] => array(C1TEXT => 0005),
        [7] => array(C1TEXT => \n),
        [8] => array(C1TEXT => 0006),
        )

$new_array = array_walk_recursive($array, 'ltrim', "\n");

echo json_encode($new_array);
2
Contributors
4
Replies
33
Views
2 Years
Discussion Span
Last Post by gabrielcastillo
1

The function array_walk_recursive will set the index key as second argument of the mapped function, the third argument will be the third of the function, since ltrim takes only two arguments it's better to define a custom function.

Now, the main problem is that array_walk_* cannot modify the structure of the array, so you cannot unset an index from the array, but you can change a value, in order to do this you must not return but simply set the value, basically:

function a(&$value, $key, $options)
{
    if(... condition ...)
        $value = '';
}

Note the reference &$value, otherwise the change is not registered by the original array.

The other problem is represented by the quotes, if in the array \n is surrounded by single quotes, then it is not consider a line feed character, but two separated characters, if instead you use double quotes you have a line feed:

$a = '\n';    # two chars
$b = "\n";    # line feed

Now, you can use a regular expression to match both cases, a pattern like this '/[\n\-n](.*)+$/' should work, and this is the full example:

<?php

    function _ltrim(&$value, $key)
    {
        preg_match('/[\n\-n](.*)+$/', $value, $match);
        if($match)
            $value = '';
    }

    $array = array(
        array('C1TEXT' => 'test'),
        array('C1TEXT' => '\n'),    # single quotes
        array('C1TEXT' => "\n"),    # double quotes
        array('C1TEXT' => '\r'),
        array('C1TEXT' => '0003'),
        );

    array_walk_recursive($array, '_ltrim');
    print print_r($array) . PHP_EOL;

It will output:

Array
(
    [0] => Array
        (
            [C1TEXT] => test
        )

    [1] => Array
        (
            [C1TEXT] => 
        )

    [2] => Array
        (
            [C1TEXT] => 
        )

    [3] => Array
        (
            [C1TEXT] => \r
        )

    [4] => Array
        (
            [C1TEXT] => 0003
        )

)

I don't know if this helps you to solve the problem, if you have to remove the empty indexes, then it's probably better to create a loop and unset from there, avoiding the array_walk_* functions.

Edited by cereal

Votes + Comments
very helpful
1

Thank you, I ended up creating a loop and doing work with jquery on the json return. Wasn't what I wanted but got the job done for now. However I will need to go back and change this to use array_walk_recursive with a custom function.

Here is what i did on the backend.

foreach ($messages as $message) {
    foreach($message as $key => $value){
        $text = $value;
        if(ord($value) == 10){
            $text = 'LF';
        }
        if(ord($value) == '13'){
            $text = '<br />';
        }
        $array[] = $text;
    }
    $string[] = trim($text);
}

echo json_encode($string);

On the frontend, I used if condition to look for LF and not display the iteration.

$.each(json, function(key, value){
    var message = value;
    if(message != "LF"){
        message = $.trim(message);
        $("ul#display-message").append('<li>'+message+'</li>');
    }                   
});

Like i said not the best way of going about it, but it worked.

My final result:

<ul id="display-message" style="list-style:none; padding-left:0;">
    <li>1UJSJ0003EB.*PKELLEY.#010030032240.</li>
    <li>HXCZ.</li>
    <li>
        <br>
    </li>
    <li>TESTING NORMAL ADMIN AGAIN NOW THAT I HAVE SET AUTOMATIC PRINT TO THE PRINTER</li>
    <li>WITH THIS MNEMONIC.</li>
</ul>
1

I see, thanks for sharing your solution! Besides my regular expression pattern was wrong, sorry for that... here's an updated version to match only \n:

$pattern = '/^([\\\\]?n|[\n])(.*)+$/';

This will catch the line feed and the \n when single quoted, in fact if you do:

$a = '\n';
echo ord($a);

You get 92 instead of 10, because it matches just the backslash. The above expression instead searches for both situations, here's a new example:

<?php

    $array = array(
        array('C1TEXT' => 'test'),
        array('C1TEXT' => '\nb'),       # single quotes
        array('C1TEXT' => "\na"),       # double quotes
        array('C1TEXT' => '\r'),
        array('C1TEXT' => '0003'),
    );

    foreach($array as $list => $lvalue)
    {
        foreach($lvalue as $key => $value)
        {
            preg_match('/^([\\\\]?n|[\n])(.*)+$/', $value, $match);
            if($match)
                unset($array[$list]);               
        }
    }

    print_r(array_merge($array));

The ending array_merge() will reindex the array and outputs:

Array
(
    [0] => Array
        (
            [C1TEXT] => test
        )

    [1] => Array
        (
            [C1TEXT] => \r
        )

    [2] => Array
        (
            [C1TEXT] => 0003
        )

)

Doing a one more step, you can use the pattern to match the carriage return, as for the line feed echo ord('\r') returns 92 instead of 13, but you can do a switch to catch the second character, i.e. r, for example:

foreach($array as $list => $lvalue)
{
    foreach($lvalue as $key => $value)
    {
        preg_match('/^([\\\\]?(n|r)|[\n|\r])(.*)+$/', $value, $match);

        if($match)
            switch(ord($match[2]))
            {
                # n
                case 110:

                # "\n" assumes 0 because:
                # $match[0] & [1] will return 10 and
                # $match[2] will be empty
                case 0:
                    unset($array[$list]);
                    break;

                # r
                case 114:
                    $array[$list][$key] = '<br />';
                    break;
            }
    }
}

The new output:

Array
(
    [0] => Array
        (
            [C1TEXT] => test
        )

    [1] => Array
        (
            [C1TEXT] => <br />
        )

    [2] => Array
        (
            [C1TEXT] => 0003
        )

)

So you won't need the extra loop to replace the carriage return with the tag. Bye!

Edited by cereal

Votes + Comments
Great solution.
0

This is a good solution.. thank you for your help. I dont know what will be in the database for the future, so the reg_ex looks like it will be the best solution.

This question has already been answered. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.