Text processing/2: Difference between revisions

m
m (→‎{{header|Raku}}: Fix comments: Perl 6 --> Raku)
m (→‎{{header|Wren}}: Minor tidy)
 
(15 intermediate revisions by 13 users not shown)
Line 24:
# Report the number of records that have good readings for all instruments.
<br><br>
 
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">V debug = 0B
V datePat = re:‘\d{4}-\d{2}-\d{2}’
V valuPat = re:‘[-+]?\d+\.\d+’
V statPat = re:‘-?\d+’
V totalLines = 0
Set[String] dupdate
Set[String] badform
Set[String] badlen
V badreading = 0
Set[String] datestamps
 
L(line) File(‘readings.txt’).read().rtrim("\n").split("\n")
totalLines++
V fields = line.split("\t")
V date = fields[0]
V pairs = (1 .< fields.len).step(2).map(i -> (@fields[i], @fields[i + 1]))
 
V lineFormatOk = datePat.match(date)
& all(pairs.map(p -> :valuPat.match(p[0])))
& all(pairs.map(p -> :statPat.match(p[1])))
I !lineFormatOk
I debug
print(‘Bad formatting ’line)
badform.add(date)
 
I pairs.len != 24 | any(pairs.map(p -> Int(p[1]) < 1))
I debug
print(‘Missing values ’line)
I pairs.len != 24
badlen.add(date)
I any(pairs.map(p -> Int(p[1]) < 1))
badreading++
 
I date C datestamps
I debug
print(‘Duplicate datestamp ’line)
dupdate.add(date)
 
datestamps.add(date)
 
print("Duplicate dates:\n "sorted(Array(dupdate)).join("\n "))
print("Bad format:\n "sorted(Array(badform)).join("\n "))
print("Bad number of fields:\n "sorted(Array(badlen)).join("\n "))
print("Records with good readings: #. = #2.2%\n".format(
totalLines - badreading, (totalLines - badreading) / Float(totalLines) * 100))
print(‘Total records: ’totalLines)</syntaxhighlight>
 
{{out}}
<pre>
Duplicate dates:
1990-03-25
1991-03-31
1992-03-29
1993-03-28
1995-03-26
Bad format:
 
Bad number of fields:
 
Records with good readings: 5017 = 91.70%
 
Total records: 5471
</pre>
 
=={{header|Ada}}==
{{libheader|Simple components for Ada}}
<langsyntaxhighlight lang="ada">with Ada.Calendar; use Ada.Calendar;
with Ada.Text_IO; use Ada.Text_IO;
with Strings_Edit; use Strings_Edit;
Line 89 ⟶ 156:
Close (File);
Put_Line ("Valid records " & Image (Count) & " of " & Image (Line_No) & " total");
end Data_Munging_2;</langsyntaxhighlight>
Sample output
<pre>
Line 101 ⟶ 168:
 
=={{header|Aime}}==
<langsyntaxhighlight lang="aime">check_format(list l)
{
integer i;
Line 153 ⟶ 220:
 
0;
}</langsyntaxhighlight>
{{out}} (the "reading.txt" needs to be converted to UNIX end-of-line)
<pre>duplicate 19900325 line
Line 161 ⟶ 228:
duplicate 19950326 line
5017 good lines</pre>
 
 
=={{header|Amazing Hopper}}==
{{Trans|AWK}}
<syntaxhighlight lang="c">
#include <basico.h>
 
algoritmo
 
número de campos correcto = `awk 'NF != 49' basica/readings.txt`
 
fechas repetidas = `awk '++count[$1] >= 2{print $1, "(",count[$1],")"}' basica/readings.txt`
 
resultados buenos = `awk '{rec++;ok=1; for(i=0;i<24;i++){if($(2*i+3)<1){ok=0}}; recordok += ok} END {print "Total records",rec,"OK records", recordok, "or", recordok/rec*100,"%"}' basica/readings.txt`
 
"Check field number by line: ", #( !(number(número de campos correcto)) ? "Ok\n" : "Nok\n";),\
"\nCheck duplicated dates:\n", fechas repetidas,NL, \
"Number of records have good readings for all instruments:\n",resultados buenos,\
"(including "
fijar separador( NL )
contar tokens en 'fechas repetidas'
" duplicated records)\n", luego imprime todo
 
terminar
</syntaxhighlight>
{{out}}
<pre>
Check field number by line: Ok
 
Check duplicated dates:
1990-03-25 ( 2 )
1991-03-31 ( 2 )
1992-03-29 ( 2 )
1993-03-28 ( 2 )
1995-03-26 ( 2 )
 
Number of records have good readings for all instruments:
Total records 5471 OK records 5017 or 91,7017 %
(including 5 duplicated records)
 
</pre>
 
=={{header|AutoHotkey}}==
 
<langsyntaxhighlight lang="autohotkey">; Author: AlephX Aug 17 2011
data = %A_scriptdir%\readings.txt
 
Line 216 ⟶ 325:
msgbox, Duplicate Dates:`n%wrongDates%`nRead Lines: %lines%`nValid Lines: %valid%`nwrong lines: %totwrong%`nDuplicates: %TotWrongDates%`nWrong Formatted: %unvalidformat%`n
</syntaxhighlight>
</lang>
 
Sample Output:
Line 243 ⟶ 352:
 
If their are any scientific notation fields then their will be an e in the file:
<langsyntaxhighlight lang="awk">bash$ awk '/[eE]/' readings.txt
bash$</langsyntaxhighlight>
Quick check on the number of fields:
<langsyntaxhighlight lang="awk">bash$ awk 'NF != 49' readings.txt
bash$</langsyntaxhighlight>
Full check on the file format using a regular expression:
<langsyntaxhighlight lang="awk">bash$ awk '!(/^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]([ \t]+[-]?[0-9]+\.[0-9]+[\t ]+[-]?[0-9]+)+$/ && NF==49)' readings.txt
bash$</langsyntaxhighlight>
Full check on the file format as above but using regular expressions allowing intervals (gnu awk):
<langsyntaxhighlight lang="awk">bash$ awk --re-interval '!(/^[0-9]{4}-[0-9]{2}-[0-9]{2}([ \t]+[-]?[0-9]+\.[0-9]+[\t ]+[-]?[0-9]+){24}+$/ )' readings.txt
bash$</langsyntaxhighlight>
 
 
Line 259 ⟶ 368:
 
Accomplished by counting how many times the first field occurs and noting any second occurrences.
<langsyntaxhighlight lang="awk">bash$ awk '++count[$1]==2{print $1}' readings.txt
1990-03-25
1991-03-31
Line 265 ⟶ 374:
1993-03-28
1995-03-26
bash$</langsyntaxhighlight>
 
 
Line 271 ⟶ 380:
 
<div style="width:100%;overflow:scroll">
<langsyntaxhighlight lang="awk">bash$ awk '{rec++;ok=1; for(i=0;i<24;i++){if($(2*i+3)<1){ok=0}}; recordok += ok} END {print "Total records",rec,"OK records", recordok, "or", recordok/rec*100,"%"}' readings.txt
Total records 5471 OK records 5017 or 91.7017 %
bash$</langsyntaxhighlight>
</div>
 
=={{header|C}}==
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <string.h>
#include <stdlib.h>
Line 360 ⟶ 469:
read_file("readings.txt");
return 0;
}</langsyntaxhighlight>
 
{{out}}
Line 374 ⟶ 483:
 
=={{header|C sharp|C#}}==
<langsyntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
Line 445 ⟶ 554:
}
}
}</langsyntaxhighlight>
 
<pre>
Line 458 ⟶ 567:
=={{header|C++}}==
{{libheader|Boost}}
<langsyntaxhighlight lang="cpp">#include <boost/regex.hpp>
#include <fstream>
#include <iostream>
Line 509 ⟶ 618:
cout << all_ok << " records were complete and ok!\n" ;
return 0 ;
}</langsyntaxhighlight>
 
{{out}}
Line 521 ⟶ 630:
1995-03-26
2004-12-31
</pre>
 
 
=={{header|Clojure}}==
<syntaxhighlight lang="clojure">
(defn parse-line [s]
(let [[date & data-toks] (str/split s #"\s+")
data-fields (map read-string data-toks)
valid-date? (fn [s] (re-find #"\d{4}-\d{2}-\d{2}" s))
valid-line? (and (valid-date? date)
(= 48 (count data-toks))
(every? number? data-fields))
readings (for [[v flag] (partition 2 data-fields)]
{:val v :flag flag})]
(when (not valid-line?)
(println "Malformed Line: " s))
{:date date
:no-missing-readings? (and (= 48 (count data-toks))
(every? pos? (map :flag readings)))}))
 
(defn analyze-file [path]
(reduce (fn [m line]
(let [{:keys [all-dates dupl-dates n-full-recs invalid-lines]} m
this-date (:date line)
dupl? (contains? all-dates this-date)
full? (:no-missing-readings? line)]
(cond-> m
dupl? (update-in [:dupl-dates] conj this-date)
full? (update-in [:n-full-recs] inc)
true (update-in [:all-dates] conj this-date))))
{:dupl-dates #{} :all-dates #{} :n-full-recs 0}
(->> (slurp path)
clojure.string/split-lines
(map parse-line))))
 
(defn report-summary [path]
(let [m (analyze-file path)]
(println (format "%d unique dates" (count (:all-dates m))))
(println (format "%d duplicated dates [%s]"
(count (:dupl-dates m))
(clojure.string/join " " (sort (:dupl-dates m)))))
(println (format "%d lines with no missing data" (:n-full-recs m)))))
</syntaxhighlight>
 
{{out}}
<pre>
5466 unique dates
5 duplicated dates [1990-03-25 1991-03-31 1992-03-29 1993-03-28 1995-03-26]
5017 lines with no missing data
</pre>
 
=={{header|COBOL}}==
{{works with|OpenCOBOL}}
<langsyntaxhighlight lang="cobol"> IDENTIFICATION DIVISION.
PROGRAM-ID. text-processing-2.
 
Line 687 ⟶ 845:
INSPECT input-data (offset:) TALLYING data-len
FOR CHARACTERS BEFORE delim
.</langsyntaxhighlight>
 
{{out}}
Line 702 ⟶ 860:
 
=={{header|D}}==
<langsyntaxhighlight lang="d">void main() {
import std.stdio, std.array, std.string, std.regex, std.conv,
std.algorithm;
Line 738 ⟶ 896:
repeatedDates.byKey.filter!(k => repeatedDates[k] > 1));
writeln("Good reading records: ", goodReadings);
}</langsyntaxhighlight>
{{out}}
<pre>Duplicated timestamps: 1990-03-25, 1991-03-31, 1992-03-29, 1993-03-28, 1995-03-26
Line 744 ⟶ 902:
 
=={{header|Eiffel}}==
<syntaxhighlight lang="eiffel">
<lang Eiffel>
class
APPLICATION
Line 860 ⟶ 1,018:
 
end
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 880 ⟶ 1,038:
=={{header|Erlang}}==
Uses function from [[Text_processing/1]]. It does some correctness checks for us.
<syntaxhighlight lang="erlang">
<lang Erlang>
-module( text_processing2 ).
 
Line 912 ⟶ 1,070:
 
value_flag_records() -> 24.
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 921 ⟶ 1,079:
 
=={{header|F Sharp|F#}}==
<langsyntaxhighlight lang="fsharp">
let file = @"readings.txt"
 
Line 941 ⟶ 1,099:
ok <- ok + 1
printf "%d records were ok\n" ok
</syntaxhighlight>
</lang>
Prints:
<langsyntaxhighlight lang="fsharp">
Date 1990-03-25 is duplicated
Date 1991-03-31 is duplicated
Line 950 ⟶ 1,108:
Date 1995-03-26 is duplicated
5017 records were ok
</syntaxhighlight>
</lang>
 
=={{header|Factor}}==
{{works with|Factor|0.99 2020-03-02}}
<syntaxhighlight lang="factor">USING: io io.encodings.ascii io.files kernel math math.parser
prettyprint sequences sequences.extras sets splitting ;
 
: check-format ( seq -- )
[ " \t" split length 49 = ] all?
"Format okay." "Format not okay." ? print ;
 
"readings.txt" ascii file-lines [ check-format ] keep
[ "Duplicates:" print [ "\t" split1 drop ] map duplicates . ]
[ [ " \t" split rest <odds> [ string>number 0 <= ] none? ] count ]
bi pprint " records were good." print</syntaxhighlight>
{{out}}
<pre>
Format okay.
Duplicates:
{
"1990-03-25"
"1991-03-31"
"1992-03-29"
"1993-03-28"
"1995-03-26"
}
5017 records were good.
</pre>
 
=={{header|Fortran}}==
Line 957 ⟶ 1,142:
Rather than copy today's data to a PDATA holder so that on the next read the new data may be compared to the old, a two-row array is used, with IT flip-flopping 1,2,1,2,1,2,... Comparison of the data as numerical values rather than text strings means that different texts that evoke the same value will not be regarded as different. If the data format were invalid, there would be horrible messages. There aren't, so ... the values should be read and plotted...
 
<syntaxhighlight lang="fortran">
<lang Fortran>
Crunches a set of hourly data. Starts with a date, then 24 pairs of value,indicator for that day, on one line.
INTEGER Y,M,D !Year, month, and day.
Line 1,020 ⟶ 1,205:
900 CLOSE(IN) !Done.
END !Spaghetti rules.
</syntaxhighlight>
</lang>
 
Output:
Line 1,032 ⟶ 1,217:
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import (
Line 1,106 ⟶ 1,291:
fmt.Println(uniqueGood,
"unique dates with good readings for all instruments.")
}</langsyntaxhighlight>
{{out}}
<pre>
Line 1,121 ⟶ 1,306:
 
=={{header|Haskell}}==
<langsyntaxhighlight lang="haskell">
import Data.List (nub, (\\))
 
Line 1,140 ⟶ 1,325:
putStr (unlines ("duplicated dates:": duplicatedDates (map date inputs)))
putStrLn ("number of good records: " ++ show (length $ goodRecords inputs))
</syntaxhighlight>
</lang>
 
this script outputs:
Line 1,156 ⟶ 1,341:
duplicated timestamps that are on well-formed records.
 
<langsyntaxhighlight lang="unicon">procedure main(A)
dups := set()
goodRecords := 0
Line 1,188 ⟶ 1,373:
}
end</langsyntaxhighlight>
 
Sample run:
Line 1,201 ⟶ 1,386:
 
=={{header|J}}==
<langsyntaxhighlight lang="j"> require 'tables/dsv dates'
dat=: TAB readdsv jpath '~temp/readings.txt'
Dates=: getdate"1 >{."1 dat
Line 1,220 ⟶ 1,405:
1992 3 29
1993 3 28
1995 3 26</langsyntaxhighlight>
 
=={{header|Java}}==
{{trans|C++}}
{{works with|Java|1.5+}}
<langsyntaxhighlight lang="java5">import java.util.*;
import java.util.regex.*;
import java.io.*;
Line 1,268 ⟶ 1,453:
}
}
}</langsyntaxhighlight>
The program produces the following output:
<pre>
Line 1,282 ⟶ 1,467:
=={{header|JavaScript}}==
{{works with|JScript}}
<langsyntaxhighlight lang="javascript">// wrap up the counter variables in a closure.
function analyze_func(filename) {
var dates_seen = {};
Line 1,331 ⟶ 1,516:
 
var analyze = analyze_func('readings.txt');
analyze();</langsyntaxhighlight>
 
=={{header|jq}}==
Line 1,337 ⟶ 1,522:
 
For this problem, it is convenient to use jq in a pipeline: the first invocation of jq will convert the text file into a stream of JSON arrays (one array per line):
<langsyntaxhighlight lang="sh">$ jq -R '[splits("[ \t]+")]' Text_processing_2.txt</langsyntaxhighlight>
 
The second part of the pipeline performs the task requirements. The following program is used in the second invocation of jq.
 
'''Generic Utilities'''
<langsyntaxhighlight lang="jq"># Given any array, produce an array of [item, count] pairs for each run.
def runs:
reduce .[] as $item
Line 1,357 ⟶ 1,542:
def is_integral: test("^[-+]?[0-9]+$");
 
def is_date: test("[12][0-9]{3}-[0-9][0-9]-[0-9][0-9]");</langsyntaxhighlight>
 
'''Validation''':
<langsyntaxhighlight lang="jq"># Report line and column numbers using conventional numbering (IO=1).
def validate_line(nr):
def validate_date:
Line 1,378 ⟶ 1,563:
def validate_lines:
. as $in
| range(0; length) as $i | ($in[$i] | validate_line($i + 1));</langsyntaxhighlight>
 
'''Check for duplicate timestamps'''
<langsyntaxhighlight lang="jq">def duplicate_timestamps:
[.[][0]] | sort | runs | map( select(.[1]>1) );</langsyntaxhighlight>
 
'''Number of valid readings for all instruments''':
<langsyntaxhighlight lang="jq"># The following ignores any issues with respect to duplicate dates,
# but does check the validity of the record, including the date format:
def number_of_valid_readings:
Line 1,395 ⟶ 1,580:
and all(range(0; 24) | $in[2*. + 2] | (is_integral and tonumber >= 1) );
 
map(select(check)) | length ;</langsyntaxhighlight>
 
'''Generate Report'''
<langsyntaxhighlight lang="jq">validate_lines,
"\nChecking for duplicate timestamps:",
duplicate_timestamps,
"\nThere are \(number_of_valid_readings) valid rows altogether."</langsyntaxhighlight>
{{out}}
'''Part 1: Simple demonstration'''
 
To illustrate that the program does report invalid lines, we first use the six lines at the top but mangle the last line.
<langsyntaxhighlight lang="sh">$ jq -R '[splits("[ \t]+")]' Text_processing_2.txt | jq -s -r -f Text_processing_2.jq
field 1 in line 6 has an invalid date: 991-04-03
line 6 has 47 fields
Line 1,421 ⟶ 1,606:
]
 
There are 5 valid rows altogether.</langsyntaxhighlight>
 
'''Part 2: readings.txt'''
<langsyntaxhighlight lang="sh">$ jq -R '[splits("[ \t]+")]' readings.txt | jq -s -r -f Text_processing_2.jq
Checking for duplicate timestamps:
[
Line 1,449 ⟶ 1,634:
]
 
There are 5017 valid rows altogether.</langsyntaxhighlight>
 
=={{header|Julia}}==
Refer to the code at https://rosettacode.org/wiki/Text_processing/1#Julia. Add at the end of that code the following:
<syntaxhighlight lang="julia">
<lang Julia>
dupdate = df[nonunique(df[:,[:Date]]),:][:Date]
println("The following rows have duplicate DATESTAMP:")
Line 1,459 ⟶ 1,644:
println("All values good in these rows:")
println(df[df[:ValidValues] .== 24,:])
</syntaxhighlight>
</lang>
{{output}}
<pre>
Line 1,503 ⟶ 1,688:
 
=={{header|Kotlin}}==
<langsyntaxhighlight lang="scala">// version 1.2.31
 
import java.io.File
Line 1,544 ⟶ 1,729:
percent = allGood.toDouble() / count * 100.0
println("Number which are all good : $allGood (${"%5.2f".format(percent)}%)")
}</langsyntaxhighlight>
 
{{out}}
Line 1,563 ⟶ 1,748:
 
=={{header|Lua}}==
<langsyntaxhighlight lang="lua">filename = "readings.txt"
io.input( filename )
 
Line 1,606 ⟶ 1,791:
for i = 1, #bad_format do
print( " ", bad_format[i] )
end</langsyntaxhighlight>
Output:
<pre>Lines read: 5471
Line 1,619 ⟶ 1,804:
 
</pre>
=={{header|M2000 Interpreter}}==
File is in user dir. Use Win Dir$ to open the explorer window and copy there the readings.txt
 
<syntaxhighlight lang="m2000 interpreter">Module TestThis {
=={{header|Mathematica}}==
Document a$, exp$
<lang Mathematica>data = Import["Readings.txt","TSV"]; Print["duplicated dates: "];
\\ automatic find the enconding and the line break
Load.doc a$, "readings.txt"
m=0
n=doc.par(a$)
k=list
nl$={
}
l=0
exp$=format$("Records: {0}", n)+nl$
For i=1 to n
b$=paragraph$(a$, i)
If exist(k,Left$(b$, 10)) then
m++ : where=eval(k)
exp$=format$("Duplicate for {0} at {1}",where, i)+nl$
Else
Append k, Left$(b$, 10):=i
End if
Stack New {
Stack Mid$(Replace$(chr$(9)," ", b$), 11)
while not empty {
Read a, b
if b<=0 then l++ : exit
}
}
Next
exp$= format$("Duplicates {0}",m)+nl$
exp$= format$("Valid Records {0}",n-l)+nl$
clipboard exp$
report exp$
}
TestThis
</syntaxhighlight>
{{out}}
<pre>
Records: 5471
Duplicate for 84 at 85
Duplicate for 455 at 456
Duplicate for 819 at 820
Duplicate for 1183 at 1184
Duplicate for 1910 at 1911
Duplicates 5
Valid Records 5017
 
</pre>
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">data = Import["Readings.txt","TSV"]; Print["duplicated dates: "];
Select[Tally@data[[;;,1]], #[[2]]>1&][[;;,1]]//Column
Print["number of good records: ", Count[(Times@@#[[3;;All;;2]])& /@ data, 1],
" (out of a total of ", Length[data], ")"]</langsyntaxhighlight>
{{out}}
 
<pre>duplicated dates:
1990-03-25
Line 1,632 ⟶ 1,866:
1993-03-28
1995-03-26
 
number of good records: 5017 (out of a total of 5471)</pre>
 
=={{header|MATLAB}} / {{header|Octave}}==
 
<langsyntaxhighlight MATLABlang="matlab">function [val,count] = readdat(configfile)
% READDAT reads readings.txt file
%
Line 1,665 ⟶ 1,898:
dix = find(diff(d)==0) % check for to consequtive timestamps with zero difference
 
printf('number of valid records: %i\n ', sum( all( val(:,5:2:end) >= 1, 2) ) );</langsyntaxhighlight>
 
<pre>>> [val,count]=readdat;
Line 1,680 ⟶ 1,913:
 
=={{header|Nim}}==
<syntaxhighlight lang="nim">import strutils, tables
<lang Nim>
import strutils, tables
 
const NumFields = 49
Line 1,687 ⟶ 1,919:
const FlagGoodValue = 1
 
var badRecords: int # the number # Number of records that have invalid formatted values.
var totalRecords: int # the total # Total number of records in the file.
var badInstruments: int # the totalTotal number of records that have at least one instrument showing error.
var seenDates: = newTableTable[string, bool]() # tableTable thatto keepskeep track of what dates we have seen.
 
proc checkFloats(floats: seq[string]): bool =
# ensure we can parse all records as floats (except the date stamp)
## Ensure we can parse all records as floats (except the date stamp).
proc checkFloats(floats:seq[string]): bool =
for index in 1..<NumFields-1:
try:
# weWe're assuming all instrument flags are floats not integers.
discard parseFloat(floats[index])
except ValueError:
Line 1,702 ⟶ 1,934:
true
 
# ensure that all sensor flags are ok
proc areAllFlagsOk(instruments: seq[string]): bool =
## Ensure that all sensor flags are ok.
#flags start at index 2, and occur every 2 fields
 
for index in countup(2,NumFields,2):
# Flags start at index 2, and occur every 2 fields.
# we're assuming all instrument flags are floats not integers
for index in countup(2, NumFields, 2):
# We're assuming all instrument flags are floats not integers
var flag = parseFloat(instruments[index])
if flag < FlagGoodValue: return false
Line 1,712 ⟶ 1,945:
 
 
# Note: we're not checking the format of the date stamp.
 
# mainMain.
var lines = readFile("readings.txt")
var currentLine: int
 
var currentLine = 0
for line in lines.splitLines:
for line in "readings.txt".lines:
currentLine.inc
if line.len == 0: continue #empty Empty lines don't count as records.
if line.len == 0: continue
var tokens = line.split({' ','\t'})
 
var tokens = line.split({' ', '\t'})
totalRecords.inc
 
if tokens.len != NumFields:
badRecords.inc
continue
Line 1,741 ⟶ 1,971:
echo tokens[DateField], " duplicated on line ", currentLine
 
varlet goodRecords = totalRecords - badRecords
varlet goodInstruments = goodRecords - badInstruments
 
echo "Total Records: ", totalRecords
echo "Good Records with wrong format: ", goodRecordsbadRecords
echo "Records where all instumentsinstruments were OK: ", goodInstruments</syntaxhighlight>
 
</lang>
{{out}}
<pre>1990-03-25 duplicated on line 85
1991-03-31 duplicated on line 456
1992-03-29 duplicated on line 820
1993-03-28 duplicated on line 1184
1995-03-26 duplicated on line 1911
Total Records: 5471
Records with wrong format: 0
Records where all instruments were OK: 5017</pre>
 
=={{header|OCaml}}==
<langsyntaxhighlight lang="ocaml">#load "str.cma"
open Str
 
Line 1,817 ⟶ 2,056:
 
Printf.printf "number of good records: %d\n" (num_good_records inputs);
;;</langsyntaxhighlight>
 
this script outputs:
Line 1,831 ⟶ 2,070:
 
=={{header|Perl}}==
<langsyntaxhighlight lang="perl">use List::MoreUtils 'natatime';
use constant FIELDS => 49;
 
Line 1,858 ⟶ 2,097:
map {" $_\n"}
grep {$dates{$_} > 1}
sort keys %dates;</langsyntaxhighlight>
 
Output:
Line 1,870 ⟶ 2,109:
 
=={{header|Phix}}==
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>sequence lines = read_lines("demo\\rosetta\\readings.txt")
<span style="color: #000080;font-style:italic;">-- demo\rosetta\TextProcessing2.exw</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> <span style="color: #000080;font-style:italic;">-- (include version/first of next three lines only)</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">readings</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> <span style="color: #000080;font-style:italic;">-- global constant lines, or:
--assert(write_lines("readings.txt",lines)!=-1) -- first run, then:
--constant lines = read_lines("readings.txt")</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">builtins</span><span style="color: #0000FF;">\</span><span style="color: #004080;">timedate</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">all_good</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">fmt</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"%d-%d-%d\t"</span><span style="color: #0000FF;">&</span><span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"%f"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">48</span><span style="color: #0000FF;">),</span><span style="color: #008000;">'\t'</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">extset</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sq_mul</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">tagset</span><span style="color: #0000FF;">(</span><span style="color: #000000;">24</span><span style="color: #0000FF;">),</span><span style="color: #000000;">2</span><span style="color: #0000FF;">),</span> <span style="color: #000080;font-style:italic;">-- {2,4,6,..48}</span>
<span style="color: #000000;">curr</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">last</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
include builtins\timedate.e
<span style="color: #004080;">string</span> <span style="color: #000000;">li</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">scanf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">li</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fmt</span><span style="color: #0000FF;">)</span>
integer all_good = 0
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r</span><span style="color: #0000FF;">)!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
 
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"bad line [%d]:%s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">li</span><span style="color: #0000FF;">})</span>
string fmt = "%d-%d-%d\t"&join(repeat("%f",48),'\t')
<span style="color: #008080;">else</span>
sequence extset = sq_mul(tagset(24),2) -- {2,4,6,..48}
<span style="color: #000000;">curr</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">][</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">3</span><span style="color: #0000FF;">]</span>
 
<span style="color: #008080;">if</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">></span><span style="color: #000000;">1</span> <span style="color: #008080;">and</span> <span style="color: #000000;">curr</span><span style="color: #0000FF;">=</span><span style="color: #000000;">last</span> <span style="color: #008080;">then</span>
--The extract routine has been added as a builtin for 0.8.0+. If you don't yet have it, just use this:
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"duplicate line for %04d/%02d/%02d\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">last</span><span style="color: #0000FF;">)</span>
--function extract(sequence source, indexes)
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
-- for i=1 to length(indexes) do
<span style="color: #000000;">last</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">curr</span>
-- indexes[i] = source[indexes[i]]
<span style="color: #000000;">all_good</span> <span style="color: #0000FF;">+=</span> <span style="color: #7060A8;">sum</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sq_le</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">extract</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">][</span><span style="color: #000000;">4</span><span style="color: #0000FF;">..$],</span><span style="color: #000000;">extset</span><span style="color: #0000FF;">),</span><span style="color: #000000;">0</span><span style="color: #0000FF;">))=</span><span style="color: #000000;">0</span>
-- end for
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
-- return indexes
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
--end function
 
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Valid records %d of %d total\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">all_good</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">)})</span>
for i=1 to length(lines) do
string li = lines[i]
sequence r = scanf(li,fmt), this, last
if length(r)!=1 then
printf(1,"bad line [%d]:%s\n",{i,li})
else
this = r[1][1..3]
if i>1 and this=last then
printf(1,"duplicate line for %04d/%02d/%02d\n",last)
end if
last = this
all_good += sum(sq_le(extract(r[1][4..$],extset),0))=0
end if
end for
<span style="color: #0000FF;">?</span><span style="color: #008000;">"done"</span>
printf(1,"Valid records %d of %d total\n",{all_good, length(lines)})</lang>
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 1,914 ⟶ 2,155:
 
=={{header|PHP}}==
<langsyntaxhighlight lang="php">$handle = fopen("readings.txt", "rb");
$missformcount = 0;
$totalcount = 0;
Line 1,948 ⟶ 2,189:
foreach ($duplicates as $key => $val){
echo $val . ' at Line : ' . $key . '<br>';
}</langsyntaxhighlight>
<pre>Valid records 5017 of 5471 total
Duplicates :
Line 1,956 ⟶ 2,197:
1993-03-28 at Line : 1184
1995-03-26 at Line : 1911</pre>
 
=={{header|Picat}}==
<syntaxhighlight lang="picat">import util.
 
go =>
Readings = [split(Record) : Record in read_file_lines("readings.txt")],
DateStamps = new_map(),
GoodReadings = 0,
foreach({Rec,Id} in zip(Readings,1..Readings.length))
if Rec.length != 49 then printf("Entry %d has bad_length %d\n", Id, Rec.length) end,
Date = Rec[1],
if DateStamps.has_key(Date) then
printf("Entry %d (date %w) is a duplicate of entry %w\n", Id, Date, DateStamps.get(Date))
else
if sum([1: I in 3..2..49, check_field(Rec[I])]) == 0 then
GoodReadings := GoodReadings + 1
end
end,
DateStamps.put(Date, Id)
end,
nl,
printf("Total readings: %d\n",Readings.len),
printf("Good readings: %d\n",GoodReadings),
nl.
 
check_field(Field) =>
Field == "-2" ; Field == "-1" ; Field == "0".</syntaxhighlight>
 
{{out}}
<pre>Entry 85 (date 1990-03-25) is a duplicate of entry 84
Entry 456 (date 1991-03-31) is a duplicate of entry 455
Entry 820 (date 1992-03-29) is a duplicate of entry 819
Entry 1184 (date 1993-03-28) is a duplicate of entry 1183
Entry 1911 (date 1995-03-26) is a duplicate of entry 1910
 
Total readings: 5471
Good readings: 5013</pre>
 
 
=={{header|PicoLisp}}==
Put the following into an executable file "checkReadings":
<langsyntaxhighlight PicoLisplang="picolisp">#!/usr/bin/picolisp /usr/lib/picolisp/lib.l
 
(load "@lib/misc.l")
Line 1,980 ⟶ 2,259:
(bye 1) ) ) ) )
 
(bye)</langsyntaxhighlight>
Then it can be called as
<pre>$ ./checkReadings readings.txt</pre>
 
=={{header|PL/I}}==
<langsyntaxhighlight lang="pli">
/* To process readings produced by automatic reading stations. */
 
Line 2,038 ⟶ 2,317:
put skip list ('There were ' || k-faulty || ' good readings' );
end check;
</syntaxhighlight>
</lang>
 
=={{header|PowerShell}}==
<langsyntaxhighlight lang="powershell">$dateHash = @{}
$goodLineCount = 0
get-content c:\temp\readings.txt |
Line 2,064 ⟶ 2,343:
}
[string]$goodLineCount + " good lines"
</syntaxhighlight>
</lang>
 
Output:
Line 2,075 ⟶ 2,354:
 
An alternative using regular expression syntax:
<langsyntaxhighlight lang="powershell">
$dateHash = @{}
$goodLineCount = 0
Line 2,096 ⟶ 2,375:
}
[string]$goodLineCount + " good lines"
</syntaxhighlight>
</lang>
 
Output:
Line 2,110 ⟶ 2,389:
=={{header|PureBasic}}==
Using regular expressions.
<langsyntaxhighlight PureBasiclang="purebasic">Define filename.s = "readings.txt"
#instrumentCount = 24
 
Line 2,181 ⟶ 2,460:
CloseConsole()
EndIf
EndIf</langsyntaxhighlight>
Sample output:
<pre>Duplicate date: 1990-03-25 occurs on lines 85 and 84.
Line 2,192 ⟶ 2,471:
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">import re
import zipfile
import StringIO
Line 2,232 ⟶ 2,511:
#readings = StringIO.StringIO(zfs.read('readings.txt'))
readings = open('readings.txt','r')
munge2(readings)</langsyntaxhighlight>
The results indicate 5013 good records, which differs from the Awk implementation. The final few lines of the output are as follows
<pre style="height:10ex;overflow:scroll">
Line 2,251 ⟶ 2,530:
* Generate mostly summary information that is easier to compare to other solutions.
 
<langsyntaxhighlight lang="python">import re
import zipfile
import StringIO
Line 2,295 ⟶ 2,574:
readings = open('readings.txt','r')
munge2(readings)</langsyntaxhighlight>
<pre>bash$ /cygdrive/c/Python26/python munge2.py
Duplicate dates:
Line 2,313 ⟶ 2,592:
 
=={{header|R}}==
<langsyntaxhighlight Rlang="r"># Read in data from file
dfr <- read.delim("d:/readings.txt", colClasses=c("character", rep(c("numeric", "integer"), 24)))
dates <- strptime(dfr[,1], "%Y-%m-%d")
Line 2,325 ⟶ 2,604:
# Number of rows with no bad values
flags <- as.matrix(dfr[,seq(3,49,2)])>0
sum(apply(flags, 1, all))</langsyntaxhighlight>
 
=={{header|Racket}}==
<langsyntaxhighlight lang="racket">#lang racket
(read-decimal-as-inexact #f)
;; files to read is a sequence, so it could be either a list or vector of files
Line 2,377 ⟶ 2,656:
 
(printf "~a records have good readings for all instruments~%"
(text-processing/2 (current-command-line-arguments)))</langsyntaxhighlight>
Example session:
<pre>$ racket 2.rkt readings/readings.txt
Line 2,404 ⟶ 2,683:
Note that we sort the pairs after we've grepped them, not before; this works fine in Raku, sorting on the key and value as primary and secondary keys. Finally, pairs and arrays provide a default print format that is sufficient without additional formatting in this case.
 
<syntaxhighlight lang="raku" perl6line>my $good-records;
my $line;
my %dates;
Line 2,422 ⟶ 2,701:
 
say 'Repeated timestamps (with line numbers):';
.say for sort %dates.pairs.grep: *.value.elems > 1;</langsyntaxhighlight>
Output:
<pre>5017 good records out of 5471 total
Line 2,451 ⟶ 2,730:
<br><br>
The program has (negated) code to write the report to a file in addition to the console.
<langsyntaxhighlight lang="rexx">/*REXX program to process instrument data from a data file. */
numeric digits 20 /*allow for bigger numbers. */
ifid='READINGS.TXT' /*name of the input file. */
Line 2,590 ⟶ 2,869:
return y//100\==0 | y//400==0 /*apply the 100 and the 400 year rule.*/
/*────────────────────────────────────────────────────────────────────────────*/
sy: say arg(1); call lineout ofid,arg(1); return</langsyntaxhighlight>
'''output''' &nbsp; when using the default input file:
<pre style="height:35ex">
Line 2,620 ⟶ 2,899:
 
=={{header|Ruby}}==
<langsyntaxhighlight lang="ruby">require 'set'
 
def munge2(readings, debug=false)
Line 2,672 ⟶ 2,951:
open('readings.txt','r') do |readings|
munge2(readings)
end</langsyntaxhighlight>
 
=={{header|Scala}}==
{{works with|Scala|2.8}}
<langsyntaxhighlight lang="scala">object DataMunging2 {
import scala.io.Source
import scala.collection.immutable.{TreeMap => Map}
Line 2,714 ⟶ 2,993:
dateMap.valuesIterable.sum))
}
}</langsyntaxhighlight>
 
Sample output:
Line 2,733 ⟶ 3,012:
 
=={{header|Sidef}}==
{{trans|Perl 6Raku}}
<langsyntaxhighlight lang="ruby">var good_records = 0;
var dates = Hash();
 
Line 2,747 ⟶ 3,026:
say "#{good_records} good records out of #{$.} total";
say 'Repeated timestamps:';
say dates.to_a.grep{ .value > 1 }.map { .key }.sort.join("\n");</langsyntaxhighlight>
{{out}}
<pre>
Line 2,758 ⟶ 3,037:
1993-03-28
1995-03-26
</pre>
 
=={{header|Snobol4}}==
 
Developed using the Snobol4 dialect Spitbol for Linux, version 4.0
 
<syntaxhighlight lang="snobol4">* Read text/2
 
v = array(24)
f = array(24)
tos = char(9) " " ;* break characters are both tab and space
pat1 = break(tos) . dstamp
pat2 = span(tos) break(tos) . *v[i] span(tos) (break(tos) | (len(1) rem)) . *f[i]
rowcount = 0
hold_dstamp = ""
num_bad_rows = 0
num_invalid_rows = 0
 
in0
row = input :f(endinput)
rowcount = rowcount + 1
row ? pat1 = :f(invalid_row)
 
* duplicated datestamp?
* if dstamp = hold_dstamp then duplicated
hold_dstamp = differ(hold_dstamp,dstamp) dstamp :s(nodup)
output = dstamp ": datestamp at row " rowcount " duplicates datestamp at " rowcount - 1
nodup
 
i = 1
in1
row ? pat2 = :f(invalid_row)
i = lt(i,24) i + 1 :s(in1)
 
* Is this a goodrow?
* if any flag is < 1 then row has bad data
c = 0
goodrow
c = lt(c,24) c + 1 :f(goodrow2)
num_bad_rows = lt(f[c],1) num_bad_rows + 1 :s(goodrow2)f(goodrow)
goodrow2
 
:(in0)
invalid_row
num_invalid_rows = num_invalid_rows + 1
:(in0)
endinput
output =
output = "Total number of rows : " rowcount
output = "Total number of rows with invalid format: " num_invalid_rows
output = "Total number of rows with bad data : " num_bad_rows
output = "Total number of good rows : " rowcount - num_invalid_rows - num_bad_rows
 
end
 
</syntaxhighlight>
{{out}}
<pre>1990-03-25: datestamp at row 85 duplicates datestamp at 84
1991-03-31: datestamp at row 456 duplicates datestamp at 455
1992-03-29: datestamp at row 820 duplicates datestamp at 819
1993-03-28: datestamp at row 1184 duplicates datestamp at 1183
1995-03-26: datestamp at row 1911 duplicates datestamp at 1910
 
Total number of rows : 5471
Total number of rows with invalid format: 0
Total number of rows with bad data : 454
Total number of good rows : 5017
</pre>
 
=={{header|Tcl}}==
 
<langsyntaxhighlight lang="tcl">set data [lrange [split [read [open "readings.txt" "r"]] "\n"] 0 end-1]
set total [llength $data]
set correct $total
Line 2,786 ⟶ 3,134:
 
puts "$correct records with good readings = [expr $correct * 100.0 / $total]%"
puts "Total records: $total"</langsyntaxhighlight>
<pre>$ tclsh munge2.tcl
Duplicate datestamp: 1990-03-25
Line 2,801 ⟶ 3,149:
To demonstate a different method to iterate over the file, and different ways to verify data types:
 
<langsyntaxhighlight lang="tcl">set total [set good 0]
array set seen {}
set fh [open readings.txt]
Line 2,839 ⟶ 3,187:
 
puts "total: $total"
puts [format "good: %d = %5.2f%%" $good [expr {100.0 * $good / $total}]]</langsyntaxhighlight>
Results:
<pre>duplicate date on line 85: 1990-03-25
Line 2,852 ⟶ 3,200:
compiled and run in a single step, with the input file accessed as a list of strings
pre-declared in readings_dot_txt
<langsyntaxhighlight Ursalalang="ursala">#import std
#import nat
 
Line 2,865 ⟶ 3,213:
#show+
 
main = valid_format?(^C/good_readings duplicate_dates,-[invalid format]-!) readings</langsyntaxhighlight>
output:
<pre>5017 good readings
Line 2,876 ⟶ 3,224:
 
=={{header|VBScript}}==
<langsyntaxhighlight lang="vb">Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile(objFSO.GetParentFolderName(WScript.ScriptFullName) &_
"\readings.txt",1)
Line 2,929 ⟶ 3,277:
 
objFile.Close
Set objFSO = Nothing</langsyntaxhighlight>
 
{{Out}}
Line 2,950 ⟶ 3,298:
* Reads flag value and checks if it is positive
* Requires 24 value/flag pairs on each line
<langsyntaxhighlight lang="vedit">#50 = Buf_Num // Current edit buffer (source data)
File_Open("|(PATH_ONLY)\output.txt")
#51 = Buf_Num // Edit buffer for output file
Line 2,997 ⟶ 3,345:
IT("Date format errors: ") Num_Ins(#14)
IT("Invalid data records:") Num_Ins(#15)
IT("Total records: ") Num_Ins(#12)</langsyntaxhighlight>
Sample output:
<langsyntaxhighlight lang="vedit">1990-03-25: duplicate record at 85
1991-03-31: duplicate record at 456
1992-03-29: duplicate record at 820
Line 3,009 ⟶ 3,357:
Date format errors: 0
Invalid data records: 454
Total records: 5471</langsyntaxhighlight>
 
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-pattern}}
{{libheader|Wren-fmt}}
{{libheader|Wren-sort}}
<syntaxhighlight lang="wren">import "io" for File
import "./pattern" for Pattern
import "./fmt" for Fmt
import "./sort" for Sort
 
var p = Pattern.new("+1/s")
var fileName = "readings.txt"
var lines = File.read(fileName).trimEnd().split("\r\n")
var count = 0
var invalid = 0
var allGood = 0
var map = {}
for (line in lines) {
count = count + 1
var fields = p.splitAll(line)
var date = fields[0]
if (fields.count == 49) {
map[date] = map.containsKey(date) ? map[date] + 1 : 1
var good = 0
var i = 2
while (i < fields.count) {
if (Num.fromString(fields[i]) >= 1) good = good + 1
i = i + 2
}
if (good == 24) allGood = allGood + 1
} else {
invalid = invalid + 1
}
}
 
Fmt.print("File = $s", fileName)
System.print("\nDuplicated dates:")
var keys = map.keys.toList
Sort.quick(keys)
for (k in keys) {
var v = map[k]
if (v > 1) Fmt.print(" $s ($d times)", k, v)
}
Fmt.print("\nTotal number of records : $d", count)
var percent = invalid/count * 100
Fmt.print("Number of invalid records : $d ($5.2f)\%", invalid, percent)
percent = allGood/count * 100
Fmt.print("Number which are all good : $d ($5.2f)\%", allGood, percent)</syntaxhighlight>
 
{{out}}
<pre>
File = readings.txt
 
Duplicated dates:
1990-03-25 (2 times)
1991-03-31 (2 times)
1992-03-29 (2 times)
1993-03-28 (2 times)
1995-03-26 (2 times)
 
Total number of records : 5471
Number of invalid records : 0 ( 0.00)%
Number which are all good : 5017 (91.70)%
</pre>
 
=={{header|zkl}}==
<langsyntaxhighlight lang="zkl"> // the RegExp engine has a low limit on groups so
// I can't use it to select all fields, only verify them
re:=RegExp(0'|^(\d+-\d+-\d+)| + 0'|\s+\d+\.\d+\s+-*\d+| * 24 + ".+$");
Line 3,030 ⟶ 3,443:
good+=1;
}
println("%d records read, %d duplicate dates, %d valid".fmt(N,dd,good));</langsyntaxhighlight>
{{out}}
<pre>
9,476

edits