Data update

This commit is contained in:
Ingy döt Net 2025-06-11 20:16:52 -04:00
parent 72eb4943cb
commit 4d5544505c
2347 changed files with 62432 additions and 16731 deletions

View file

@ -0,0 +1,164 @@
BEGIN # Test processing/2 - using thee file from Text processing/1, #
# verify the format, detect duplicate dates and #
# count the number of records with all instruments #
# functioning #
PR read "files.incl.a68" PR # include file utilities: EACHLINE, etc. #
CHAR tab = REPR 9;
INT instruments = 24; # expected number of instrument readings #
MODE READING = STRUCT( STRING date
, [ 1 : instruments ]REAL data
, [ 1 : instruments ]INT status
, BOOL format ok
, STRING message
);
OP INIT = ( REF READING r )VOID:
BEGIN
FOR n TO instruments DO ( data OF r )[ n ] := ( status OF r )[ n ] := 0 OD;
format ok OF r := TRUE;
date OF r := "";
message OF r := ""
END # INIT # ;
INT all good count := 0; # number of lines which have all instruments ok #
STRING last date := ""; # date of the previous line #
# return the date and instrument readings and status values on the line #
PROC parse readings = ( STRING line )READING:
BEGIN
BOOL data error := FALSE;
# returns v converted to a REAL, returns 0 and sets data error #
# to TRUE if v is invalid #
OP TOREAL = ( STRING v )REAL:
BEGIN
REAL value := 0;
FILE real value;
associate( real value, LOC STRING := v );
on value error
( real value
, ( REF FILE ef )BOOL: # "handles" invalid data and #
BEGIN # returns TRUE so processing #
value := 0; # can continue #
data error := TRUE
END
);
get( real value, value );
close( real value );
value
END # TOREAL # ;
# returns v converted to an INT, returns 0 and sets data error #
# to TRUE if v is invalid #
OP TOINT = ( STRING text )INT:
BEGIN
INT value := 0;
BOOL is numeric := TRUE;
FOR ch pos FROM UPB text BY -1 TO LWB text WHILE is numeric DO
CHAR c = text[ ch pos ];
IF c = "-"
THEN value := - value;
is numeric := ch pos = LWB text AND ch pos /= UPB text
ELSE is numeric := is numeric AND c >= "0" AND c <= "9";
IF is numeric THEN ( value *:= 10 ) +:= ABS c - ABS "0" FI
FI
OD;
IF NOT is numeric THEN data error := TRUE FI;
value
END # TOINT # ;
# superficially checks v is in the format yyyy-mm-dd #
PROC check date format = ( STRING v )BOOL:
BEGIN
STRING ymd := v[ AT 1 ];
IF NOT ( data error := UPB ymd /= 10 ) THEN
# length is correct for yyyy-mm-dd #
IF NOT ( data error := ymd[ 5 ] /= "-" OR ymd[ 8 ] /= "-" ) THEN
INT d;
d := ( TOINT ymd[ 1 : 4 ] * 10000 )
+ ( TOINT ymd[ 6 : 7 ] * 100 )
+ TOINT ymd[ 9 : 10 ]
FI
FI;
NOT data error
END # check date format # ;
READING result; INIT result;
INT c pos := LWB line;
INT max pos = UPB line;
INT field number := 0;
WHILE c pos <= max pos DO
# skip leading spaces and tabs #
WHILE IF c pos > max pos
THEN FALSE
ELSE CHAR ch = line[ c pos ]; ch = " " OR ch = tab
FI
DO c pos +:= 1 OD;
IF c pos <= max pos THEN # have a field #
INT start pos = c pos;
WHILE IF c pos > max pos
THEN FALSE
ELSE CHAR ch := line[ c pos ]; ch /= " " AND ch /= tab
FI
DO c pos +:= 1 OD;
STRING f := line[ start pos : c pos - 1 ];
IF ( field number +:= 1 ) = 1 THEN # the date #
IF NOT check date format( f ) THEN
format ok OF result := FALSE;
message OF result := "Invalid date: " + f
FI;
date OF result := f
ELIF INT instrument = field number OVER 2;
instrument > instruments THEN
format ok OF result := FALSE; # too many readings #
message OF result := "Too many instruments"
ELIF ODD field number THEN
# field 3, 5, 7... the instrument state of reading #
( status OF result )[ field number OVER 2 ] := TOINT f;
IF data error THEN
format ok OF result := FALSE;
message OF result := "Invalid status for instrument " + whole( instrument, 0 )
FI
ELSE # must be the instrument reading #
( data OF result )[ field number OVER 2 ] := TOREAL f;
IF data error THEN
format ok OF result := FALSE;
message OF result := "Invalid reading for instrument " + whole( instrument, 0 )
FI
FI
FI
OD;
IF format ok OF result AND field number /= 2 * instruments + 1 THEN
format ok OF result := FALSE;
message OF result := "Incorrect number of readings/status values"
FI;
result
END # parse readings # ;
# checks the readings and date on line #
PROC check readings = ( STRING line, INT line count )BOOL:
BEGIN
READING data := parse readings( line );
IF format ok OF data AND line count > 1 AND date OF data = last date THEN
format ok OF data := FALSE;
message OF data := "Duplicate date: " + date OF data
FI;
IF NOT format ok OF data THEN # line has invalid data #
print( ( "Line: ", whole( line count, 0 ), ": ", message OF data, newline ) )
ELSE # the line appears ok #
BOOL all good := TRUE;
FOR i TO instruments WHILE all good := ( status OF data )[ i ] > 0 DO SKIP OD;
IF all good THEN all good count +:= 1 FI;
last date := date OF data
FI;
TRUE
END # check readings # ;
IF STRING file name = "readings.txt";
INT total lines = file name EACHLINE check readings;
total lines < 0
THEN print( ( "Unable to open ", file name, newline ) )
ELSE print( ( whole( total lines, 0 ), " lines in ", file name, ", " ) );
print( ( whole( all good count, 0 ), " have all instruments in a good state.", newline ) )
FI
END

View file

@ -0,0 +1,128 @@
#include "datetime.bi"
Const filename = "readings.txt"
Const readings = 24 ' per line
Const fields = readings*2 + 1 ' per line
Const dateFormat = "%Y-%m-%d"
Type DateRecord
fecha As String
hasGoodRecord As Boolean
End Type
' Array to store unique dates
Dim Shared As DateRecord dateRecords(Any)
' Function to check if a fecha exists in our array
Function findDate(dateArray() As DateRecord, dateStr As String, count As Integer) As Integer
For i As Integer = 0 To count - 1
If dateArray(i).fecha = dateStr Then Return i
Next
Return -1
End Function
Sub main()
Dim As Integer ff, flag, dateIndex, i, partCount
Dim As Integer allGood = 0, uniqueGood = 0, dateCount = 0
Dim As String linea, dateStr, currentPart, c
Dim As Double value
Dim As Boolean good
ff = Freefile
If Open(filename For Input As #ff) <> 0 Then
Print "Error: Could not open file '" & filename & "'"
Exit Sub
End If
' Process each line
While Not Eof(ff)
Line Input #ff, linea
' Split the line into fields
Dim As String parts(0 To fields-1)
partCount = 0
currentPart = ""
' Optimized string parsing
For i = 1 To Len(linea)
c = Mid(linea, i, 1)
If c = " " Or c = Chr(9) Then ' Space or Tab
If Len(currentPart) > 0 Then
parts(partCount) = currentPart
partCount += 1
currentPart = ""
End If
Else
currentPart &= c
End If
Next
' Add the last part if it exists
If Len(currentPart) > 0 Then
parts(partCount) = currentPart
partCount += 1
End If
' Check if we have the expected number of fields
If partCount <> fields Then
Print "Error: Unexpected format, " & partCount & " fields."
Close #ff
Exit Sub
End If
' Get the date
dateStr = parts(0)
' Check if all readings are good
good = True
For i = 1 To fields-1 Step 2
flag = Val(parts(i+1))
If flag > 0 Then
value = Val(parts(i))
If value = 0 And parts(i) <> "0" And parts(i) <> "0.000" Then
Print "Error: Could not convert '" & parts(i) & "' to integer."
Close #ff
Exit Sub
End If
Else
good = False
Exit For
End If
Next
If good Then allGood += 1
dateIndex = findDate(dateRecords(), dateStr, dateCount)
If dateIndex >= 0 Then
Print "Duplicate datestamp: " & dateStr
If good And Not dateRecords(dateIndex).hasGoodRecord Then
dateRecords(dateIndex).hasGoodRecord = True
uniqueGood += 1
End If
Else
' New date
If dateCount > Ubound(dateRecords) Then
Redim Preserve dateRecords(Ubound(dateRecords) + 100)
End If
dateRecords(dateCount).fecha = dateStr
dateRecords(dateCount).hasGoodRecord = good
If good Then uniqueGood += 1
dateCount += 1
End If
Wend
Close #ff
Print !"\nData format valid."
Print allGood & " records with good readings for all instruments."
Print uniqueGood & " unique dates with good readings for all instruments."
End Sub
main()
Sleep

View file

@ -5,10 +5,7 @@ dates = {}
duplicated, bad_format = {}, {}
num_good_records, lines_total = 0, 0
while true do
line = io.read( "*line" )
if line == nil then break end
for line in io.lines() do
lines_total = lines_total + 1
date = string.match( line, "%d+%-%d+%-%d+" )

View file

@ -0,0 +1,42 @@
include xpllib; \for Print, StrCmp and StrCopy
int Records, Invalid, AllGood;
char File_name, C, Date(10+1), LastDate(10+1);
int N, Flag, Count;
real Data;
[File_name:= "readings.txt";
Print("File = %s\n", File_name);
Print("\nDuplicated dates:\n");
FSet(FOpen(File_name, 0), ^i); OpenI(3);
Records:= 0; Invalid:= 0; AllGood:= 0;
LastDate(0):= 0;
loop
[for N:= 0 to 10-1 do
[C:= ChIn(3);
if C = LF then C:= ChIn(3);
if C = EOF then quit;
Date(N):= C;
];
Date(N):= 0;
if Date(0)#^1 and Date(0)#^2 then Invalid:= Invalid+1;
if StrCmp(Date, LastDate) = 0 then
Print("%s\n", Date);
StrCopy(LastDate, Date);
Records:= Records+1;
Count:= 0;
for N:= 0 to 24-1 do
[Data:= RlIn(3);
Flag:= IntIn(3);
if Flag > 0 then
Count:= Count+1;
];
if Count = 24 then AllGood:= AllGood+1;
];
Print("\nTotal number of records : %d\n", Records);
Print("Number of invalid records : %d\n", Invalid);
Print("Number which are all good : %d (%1.2f^%)\n",
AllGood, float(AllGood)/float(Records)*100.0);
]