pedaars
pedaars

Reputation: 161

How to parse lines of formatted text into an array of objects?

I am trying to build a multidimensional array in PHP using an array of string that I am cutting up so the string of 1:[email protected]:7:8.35 becomes

"id": "1",  
"email_address": "[email protected]",  
"domain": "yahoo.com",  
"number_of_orders": "7",    
"total_order_value": "£8.35"

In JavaScript I would create an object containing the above values and put it into an array but what is the equivalent in PHP? So far I have the below code which gives me

Array ( [0] => stdClass Object ( [id] => 1 [email] => [email protected] [domain] => yahoo.com [number_of_orders] => 7 [total_order_value] => 8.35 )

<?php

$data = file_get_contents('orderdata');
/* echo $data; */

$lines = explode("\n", $data);

array_splice($lines, 0, 8);
/* var_dump($lines); */

array_splice($lines, -3);
/* var_dump($lines); */

/* removes all NULL, FALSE and Empty Strings but leaves 0 (zero) values */
$lines = array_values(array_filter($lines, 'strlen'));


function arraySort($lines ,$i) {
    $rep = new stdClass();
    $rep->id = strId($lines, $i);
    $rep->email = strEmail($lines, $i);
    $rep->domain = strDomain($lines, $i);
    $rep->number_of_orders = orderNo($lines, $i);
    $rep->total_order_value = orderValue($lines, $i);
    /* var_dump($rep); */
    return $rep;
}


function strDomain($lines, $i) {
    if($lines[$i] == null){
        return "";
    } 
    else {
        $str = $lines[$i];
        $splt = explode(':', $str);
        $domain = explode('@', $splt[1]);
        return $domain[1];
    }
}


function strId($lines, $i) {
    if($lines[$i] == null){
        return "";
    } 
    else {
        $str = $lines[$i];
        $splt = explode(':', $str);
        return $splt[0];
    }
    
}


function strEmail($lines, $i) {
    if($lines[$i] == null){
        return "";
    } 
    else {
        $str = $lines[$i];
        $splt = explode(':', $str);
        return $splt[1];
    }
}


function orderNo($lines, $i) {
    if($lines[$i] == null){
        return "";
    } 
    else {
        $str = $lines[$i];
        $splt = explode(':', $str);
        return $splt[2];
    }
}


function orderValue($lines, $i) {
    if($lines[$i] == null){
        return "";
    } 
    else {
        $str = $lines[$i];
        $splt = explode(':', $str);
        return '£' + $splt[3];
    }
}

$reports = array();
$reps = array();
for($i = 0, $length = count($lines); $i < $length; ++$i) {
    $reps = arraySort($lines, $i);
    array_push($reports, $reps);
}

?>

but when I try to search the array with

$filteredArray = 
array_filter($reports, function($element) use($search){
  return isset($element['domain']) && $element['domain'] == $search;
});

I get the following error

Fatal error: Uncaught Error: Cannot use object of type stdClass as array in phpData.php:110 Stack trace: #0 [internal function]: {closure}(Object(stdClass)) #1 phpData.php(111): array_filter(Array, Object(Closure)) #2 {main} thrown in phpData.php on line 110

Is this because of the use of $rep = new stdClass();in my arraySort function? If so what should I be using?

Upvotes: 4

Views: 141

Answers (3)

mickmackusa
mickmackusa

Reputation: 47761

By duplicating the domain substring and injecting a delimiter before exploding and prepending the British pound symbol on the last value, you can immediately parse the line of text and have all associative elements in the desired order. Demo

$line = '1:[email protected]:7:8.35';
var_export(
    array_combine(
        ['id', 'email_address', 'domain', 'number_of_orders', 'total_order_value'],
        explode(
            ':',
            preg_replace(
                // inject domain, prepend currency symbol
                ['#@([^:]*)\K#', '#:\K(?=[^:]+$)#'],
                [':$1', '£'],
                $line
            )
        )
    )
);

You can cast this an array to an object if you like -- just append (object) before the array payload.

$reports[] = (object) array_combine(
    ['id', 'email_address', 'domain', 'number_of_orders', 'total_order_value'],
    explode(
        ':',
        preg_replace(
            ['#@([^:]*)\K#', '#:\K(?=[^:]+$)#'],
            [':$1', '£'],
            $line
        )
    )
);

The replacement steps:

  • capture the substring after @ until before the next colon, then re-inject that substring as a new delimited value in the next position.
  • match the last occurring colon and if it is followed by any characters, prepend the pound symbol.

p.s. arraySort() is not an ideal name for a function that parses text into an object. Even parseLine() would be more intuitive.

Upvotes: 0

r&#252;ff0
r&#252;ff0

Reputation: 943

you can use object obtention method like this:

$filteredArray = 
array_filter($reports, function($element) use($search){
  return isset($element->domain) && $element->domain == $search;
});

Upvotes: 0

Julien Lachal
Julien Lachal

Reputation: 1141

The easiest and shortest solution would be :

$value = "1:[email protected]:7:8.35";
$keys = array('id', 'email_address', 'number_of_orders', 'total_order_value');
$fused = array_combine($keys, explode(':', $value));
$fused['domain'] = strDomain($fused['email_address']); //using your "strDomain()" function

It will give you the array you want, except you won't have the £ sign in your order value.

Upvotes: 2

Related Questions