Vinnaren i pepparkakshustävlingen!
2020-12-08, 12:12
  #1
Medlem
Hej,

Sitter med ett litet php projekt inom ett område jag aldrig tidigare arbetat med.
Jag har en textfil som autogenereras från ett program, där varje rad skall läggas in i en array så att jag kan skriva ut värdena på en sida för översikt.

txt filen ser ut såhär och det är så jag vill ha den utskriven på sidan:

Kod:
1614566 00:05:39 25-01-20 MODE-1 NUMERIC 1200    754Å0754Å016500

0273069 00:11:33 25-01-20 MODE-2 ALPHA   1200    *U*U*U*U*U*U*U

1398101 00:11:39 25-01-20 MODE-3 NUMERIC 1200    ÄÄÄÄÄ49738854Å*

1573496 00:11:40 25-01-20 MODE-1 ALPHA   1200    J0f? H2`?Q?OqA

1278767 00:14:30 25-01-20 MODE-4 NUMERIC 1200    938UÅ
1066785 00:14:38 25-01-20 MODE-1 NUMERIC 1200    11125
1280683 00:14:41 25-01-20 MODE-2 NUMERIC 1200    ****************8U*ÄÄÄÄÄU
					         ******
0024042 14:35:51 25-01-20 MODE-2 ALPHA   1200    =EÖ^"./?WWHs?rx
                                                 9<E?^"?/?GWH

Problemet är att den sista raden har radbrytningar och hamnar istället på den första raden. Jag är väl ganska säker på att det är preg_split som påverkar detta och det är där jag är helt borta.

Såhär blir det istället:

Kod:
1614566	00:05:39	25-01-20	MODE-1	NUMERIC	1200	754Å0754Å016500
0273069	00:11:33	25-01-20	MODE-2	ALPHA	1200	*U*U*U*U*U*U*U
1398101	00:11:39	25-01-20	MODE-3	NUMERIC	1200	ÄÄÄÄÄ49738854Å*
1573496	00:11:40	25-01-20	MODE-1	ALPHA	1200	J0f?
1278767	00:14:30	25-01-20	MODE-4	NUMERIC	1200	938UÅ
1066785	00:14:38	25-01-20	MODE-1	NUMERIC	1200	11125
1280683	00:14:41	25-01-20	MODE-2	NUMERIC	1200	****************8U*ÄÄÄÄÄU
******					
0024042	14:35:51	25-01-20	MODE-2	ALPHA	1200	=EÖ^"./?WWHs?rx
9					

Av någon anledning så försvinner halva meddelandet efter 9 på sista raden, det har jag inte lyckats åtgärda alls. Jag får även otroligt många "Notice: Undefined offset: x". Jag vill egentligen bara att den skall gå vidare efter varje radbrytning och det är väl därför sista raden har också stryker med.

Kod:
$file_handle fopen("lib/200125.log""r");

        echo 
"<table>";
             while (!
feof($file_handle) ) {
        
$line_of_text utf8_encode(fgets($file_handle));
        
$parts preg_split('/[\s]+/',  $line_of_text);
        echo 
        
"<tr>
        <td>" 
$parts[0] . "</td>
        <td>" 
$parts[1] . "</td>
        <td>" 
$parts[2] . "</td>
        <td>" 
$parts[3] . "</td>
        <td>" 
$parts[4] . "</td>
        <td>" 
$parts[5] . "</td>
        <td>" 
$parts[6] . "</td>
        </tr>"
;

        }

        
fclose($file_handle);

      
?> 

Tacksam för hjälp!
Citera
2020-12-09, 01:09
  #2
Medlem
Hastigt och lustigt.. Det går kanske att fila på så att man slipper alla trim() och count()? Feedback mottages.. Min idé var väl att man inte behöver skriva ut en rad direkt bara för att man läser in den. Kändes som att det blev enklare då.. Lite formaterat för kommandorad också, det var där jag testkörde. Hårdkodade array-index.. En rätt specifik lösning, helt enkelt.

Kod:
$file_handle fopen("test.txt""r");

$rows = [];
while (!
feof($file_handle) ) {
    
$line_of_text utf8_encode(fgets($file_handle));
    
preg_match('/(.+?)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+)/'$line_of_text$parts);
    
    if (
count($parts) != 8) {
        continue;
    }

    
// Om första platsen är tom så antar vi att det är text-fältet som ska fyllas på.
    // Om det finns fler varianter att tänka på här så behövs flera tester, så klart..
    
if (trim($parts[1]) == '') {
        
// Bygg på textfältet i senaste fullständiga raden
        
$rows[count($rows)-1][7] .= "\n".$parts[7];
    }
    else {
        
$rows []= $parts;
    }
}

fclose($file_handle);

echo 
"<table>\n";
foreach(
$rows as $row) {
    echo 
        
"<tr>".
        
"<td>" $row[1] . "</td>".
        
"<td>" $row[2] . "</td>".
        
"<td>" $row[3] . "</td>".
        
"<td>" $row[4] . "</td>".
        
"<td>" $row[5] . "</td>".
        
"<td>" $row[6] . "</td>".
        
"<td>" nl2br($row[7]) . "</td>".
        
"</tr>\n";

__________________
Senast redigerad av Koenigsegg 2020-12-09 kl. 01:13.
Citera
2020-12-09, 11:48
  #3
Medlem
Annan version om du inte vill ladda in allt i minnet innan det skrivs ut.. Lite förkortad, men det går förhoppningsvis att gissa hur printRow() ser ut.

Kod:
$prev_row null;
while (!
feof($file_handle) ) {
    
$line_of_text utf8_encode(fgets($file_handle));
    
preg_match('/(.+?)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+)/'$line_of_text$row);
    
    if (
count($row) != 8) {
        continue;
    }

    if (
trim($row[1]) == '') {
        
$prev_row[7] .= "\n".$row[7];
        continue;
    }

    if (
$row !== null) {
        
printRow($prev_row);
    }
    
    
$prev_row $row;
}

printRow($prev_row);

fclose($file_handle); 
Citera
2020-12-10, 21:13
  #4
Medlem
SKetchers avatar
Citat:
Ursprungligen postat av Koenigsegg
Annan version om du inte vill ladda in allt i minnet innan det skrivs ut.. Lite förkortad, men det går förhoppningsvis att gissa hur printRow() ser ut.

Jag förutsätter att hela textfilen har samma konsekventa formattering?
Raderna i texten är avdelade med en tabb vilket har "\t" som karaktär.
Skulle rekommendera att skippa regexen helt och använda samma sätt att formattera som programmet som skapade filen.

Kod:
str_getcsv($, "\t"); 
regex kan bli omständigt med långa regler som inte täcker alla corner-cases. Gör det simpelt om det går.


Kod:
<?php
<?php
$handle 
fopen("data.txt""r");
$data = [];

while ((
$raw_string fgets($handle)) !== false) {
    
$data[] = str_getcsv($raw_string"\t");
}
fclose($handle);

$bad_rows = [];
foreach (
$data as $key => $val) {

    if (
in_array(""$val)) {
        
$bad_rows[] = $key;
        if (isset(
$data[$key 1])) {
            foreach (
$val as $k => $v) {
                
$data[$key 1][count($data[$key 1]) - 1] .= $v;
            }
        }
        continue;
    }
}

foreach (
$bad_rows as $val) {
    unset(
$data[$val]);
}

var_dump($data);

Jag är inne på samma lösning som du. Att när ett array-element innehåller invalid data(i det här fallet tomma strängar), lägg till elementen på raden innan och ta bort den.

När det gäller att displaya data så ser jag det som komplett irrelevant i PHP. I vanliga strukterade fall ska det läggas i ett viewlager, annars så dumpa ut det i så simplifierad form som möjligt. Blir ofta slöseri med tid att sitta och försöka pussla ihop utseende blandat med logik.

Kod:
$bad_rows 
är en array som håller koll på vilka rader som är dåliga.
I slutet gör vi en unset för att rensa dessa rader och inte mitt under loopen för att bugga med iterationen.

Kod:
var_dump 
Världens överlägset bästa funktion. Delad förstaplats med javascripts console.log
__________________
Senast redigerad av SKetcher 2020-12-10 kl. 21:18.
Citera
2020-12-10, 23:45
  #5
Medlem
Citat:
Ursprungligen postat av SKetcher
Jag förutsätter att hela textfilen har samma konsekventa formattering?
Raderna i texten är avdelade med en tabb vilket har "\t" som karaktär.
Tab-tecken kommer inte förrän på tredje raden från slutet(i dumpen i trådstarten, markera text med musen så syns det). På raderna ovanför så är fälten skilda åt av varierande antal mellanslag. Så om man vill hantera det där som CSV så skulle jag nog kalla det formatering från avgrunden :-].. Men visst hade det varit lättare! Bara citat-tecken runt fälten med mellanslag i sig som hade fattats då.

Citat:
Ursprungligen postat av SKetcher
Skulle rekommendera att skippa regexen helt och använda samma sätt att formattera som programmet som skapade filen.
Och vad är mallen som programmet som skapade filen använde, då? Regexp finns inte där för att vi ska undvika att använda dem. Om det finns ett annat sätt så är det förmodligen enklare att använda, jag håller helt med om det. Men i det här fallet? Fältavskiljare är mellanslag. Möjligen så skulle jag kunna tänka mig att använda sån avläsning(CSV med mellanslag) här om det fanns ett konstant antal "dummy-kolumner". Men när sista kolumnen innehåller mellanslag? Då hoppar hörn-fallen dit från regexpen..

Citat:
Ursprungligen postat av SKetcher
regex kan bli omständigt med långa regler som inte täcker alla corner-cases. Gör det simpelt om det går.
<Retorisk fråga>Vänligen definiera "går"..</Retorisk fråga>

Citat:
Ursprungligen postat av SKetcher
Kod:
<?php
...
    
$data[] = str_getcsv($raw_string"\t");
Som sagts ovan, det där blir fel på första raden eftersom avskiljaren inte stämmer med texten.

Citat:
Ursprungligen postat av SKetcher
När det gäller att displaya data så ser jag det som komplett irrelevant i PHP. I vanliga strukterade fall ska det läggas i ett viewlager, annars så dumpa ut det i så simplifierad form som möjligt. Blir ofta slöseri med tid att sitta och försöka pussla ihop utseende blandat med logik.
Förhoppningsvis så är server-genererad HTML mindre vanlig numera, ja :-]! Det skulle vi kunna fylla en tråd med.
__________________
Senast redigerad av Koenigsegg 2020-12-11 kl. 00:16.
Citera
2020-12-11, 00:23
  #6
Medlem
SKetchers avatar
Citat:
Ursprungligen postat av Koenigsegg
Tab-tecken kommer inte förrän på tredje raden från slutet(i dumpen i trådstarten, räcker att markera text med musen så syns det). På raderna ovanför så är fälten skilda åt av varierande antal mellanslag. Så om man vill hantera det där som CSV så skulle jag nog kalla det formatering från avgrunden :-].. Men visst hade det varit lättare! Bara citat-tecken runt fälten med mellanslag i sig som hade fattats då.


Och vad är mallen som programmet som skapade filen använde, då? Regexp finns inte där för att vi ska undvika att använda dem. Om det finns ett annat sätt så är det förmodligen enklare att använda, jag håller helt med om det. Men i det här fallet? Fältavskiljare är mellanslag. Möjligen så skulle jag kunna tänka mig att använda sån avläsning(CSV med mellanslag) här om det fanns ett konstant antal "dummy-kolumner". Men när sista kolumnen innehåller mellanslag? Då hoppar hörn-fallen dit från regexpen..


Vänligen definiera "går"..


Som sagts ovan, det där blir fel på första raden eftersom avskiljaren inte stämmer med texten.


Förhoppningsvis så är server-genererad HTML mindre vanlig numera, ja :-]. Det skulle vi kunna fylla en tråd med.
Jag kopierade texten från TS andra citat-ruta vilket har \t mellan kolumnerna. Jag antar att han tabbat själv då det inte ingick i hans kod. Blandade för övrigt ihop er två och trodde han skrivit alla inläggen där han plötsligt utvecklat sin kod rejält.
Jag gillade inte sättet han delade upp $parts från preg_match i första inlägget, så var för att leda in honom på ett annat spår. Men om det nu inte finns tabbar i det här fallet så är Regex är ett bra val.
Ett klassiskt alternativ är en kombination av explodes och trims, men det kräver fler kodrader och ser inte lika ballt ut.
__________________
Senast redigerad av SKetcher 2020-12-11 kl. 00:30.
Citera
2020-12-11, 00:26
  #7
Medlem
SKetchers avatar
Citat:
Ursprungligen postat av Koenigsegg
<Retorisk fråga>Vänligen definiera "går"..</Retorisk fråga>
Som nämnt. Hans andra citatruta hade dessa tabbar, så det var mitt antagande att dem fanns där.

Citat:
Ursprungligen postat av Koenigsegg
Som sagts ovan, det där blir fel på första raden eftersom avskiljaren inte stämmer med texten.
Se innan

Citat:
Ursprungligen postat av Koenigsegg
Förhoppningsvis så är server-genererad HTML mindre vanlig numera, ja :-]! Det skulle vi kunna fylla en tråd med.
Japp. Blir dessutom komplett oläsligt i konsollruta >
Citera

Stöd Flashback

Flashback finansieras genom donationer från våra medlemmar och besökare. Det är med hjälp av dig vi kan fortsätta erbjuda en fri samhällsdebatt. Tack för ditt stöd!

Stöd Flashback