23. juni 2015 - 06:49 Der er 14 kommentarer

*.CMD script til fil/tekst manipulation ?

Hi Windows Batch / Script fil 'freaks' :-)

Jeg har en laaaang tekstfil (>100.000 linier) med (eksempelvis) følgende:

21-05-2015 12:56 976.004 BHAU0004_PC2362A.log
26-05-2015 19:18 35.753 RLAN0002_PC4141A.log
19-05-2015 11:35 794.638 HROS0005_PC6912A.log
23-04-2015 16:49 36.433 LHEN0087_PC6131A.log
10-06-2015 14:19 625.593 HKAV0001_PC1151.log

Feltseperatoren er altid " " eller _ eller .
Jeg skal have den sorteret til at se sådan ud (fra ovenstående eksempel)

PC2362A BHAU0004 21-05-2015 12:56
PC4141A RLAN0002 26-05-2015 19:18
PC6912A HROS0005 19-05-2015 11:35
PC6131A LHEN0087 23-04-2015 16:49
PC1151 HKAV0001 10-06-2015 14:19

Det SKAL være i et *.CMD / *.BAT script da det skal bygges sammen med 'noget' andet automatisk ...
Jeg ved der er fil/streng manipulations muligheder på en måde :-)

Hvad ka' du byde på?

Evt. links til eksempler, da jeg vil 'lege' videre med det ...
Avatar billede Spotgun Seniormester
23. juni 2015 - 08:30 #1
Sjov lille opgave :) Prøv med dette script:


@ECHO Off

SET InputFile=Data.txt

REM * For hver linie i input filen
FOR /F "tokens=*" %%A IN (%InputFile%) DO (
    REM * Kald subroutine, da variabler først behandles efter DO
    CALL :ParseString "%%A"
)

:ParseString
REM * Sæt input til en temp variabel vi kan manipulere med
SET _TempString=%1
REM * Erstat underscores med mellemrum
SET _TempString=%_TempString:_= %
REM * Fjern gåseøjne fra start og slut (kommer på fra kaldet af subroutinen)
SET _TempString=%_TempString:~1,-1%
REM * Fjern ".log" fra filnavnet
SET _TempString=%_TempString:.log= %
REM * Split strengen op i fem individuelle variabler
FOR /F "tokens=1-5* delims= " %%A IN ("%_TempString%") DO (
    REM * Spring en linie over som starter med "=" (sker åbenbart ifm. opslitning)
    IF NOT "%%A" == "=" (
        REM * Udskriv i det format du ønsker
        ECHO %%E %%D %%A %%B
    )
)
GOTO :EOF
23. juni 2015 - 10:08 #2
Ser ganske fornuftigt / forståeligt ud ... mulighed for at jeg selv kan bygge lidt extra + formatering af input/output på ...

Info følger  ...
24. juni 2015 - 10:28 #3
<spotgun>: Det virker faktisk ... kørte en stor fil (~100.000 linier)i går aftes ... tog sin tid ... men resultatet er som ønsket !!!

Så vil jeg gerne have Output 'formateret' til at hvert felt/variable skal stå pænt i samme kolonne ... altså formateret så eksempelvis

%E -> 20 tegn
%D -> 20 tegn
%A -> 15 tegn
%B -> 10 tegn

hvordan gør man det ?
Avatar billede Spotgun Seniormester
24. juni 2015 - 10:49 #4
ECHO kommandoen har mig bekendt ikke nogen muligheder for at formatere outputtet. Og jeg er ikke bekendt med andre batch kommandoer som kan.

Jeg tænker det vil række for vidt, selv at strikke en metode sammen til at kunne formatere outputtet.
Avatar billede tryltryl Juniormester
25. juni 2015 - 14:37 #5
Prøv:

SET A1=%%A                    "
SET B1=%%B                    "
SET E1=%%E                    "
SET D1=%%D                    "
ECHO !E1:~0,20! !D1:~0,20! !A1:~0,15! !B1:~0,10!

og tilføj efter echo off:
SETLOCAL ENABLEDELAYEDEXPANSION
Avatar billede ejvindh Ekspert
25. juni 2015 - 14:51 #6
Alternativt kunne du jo også overveje enten at flytte filnavnene hen til slut (det er vel primært dem, der kan variere i længde).

Eller du kan erstatte mellemrum med <tab> -- det vil fange de fleste tilfælde af uens længde.

Fandt også en metode til at indføre fast streng-længde her:
http://stackoverflow.com/questions/13398545/string-processing-in-windows-batch-files-how-to-pad-value-with-leading-zeros

Men da jeg ikke selv kører med windows mere, kan jeg ikke checke om det virker.
25. juni 2015 - 20:53 #7
Ref #5: Det ser forståelige ud ... skal straks afprøves i morgen :-)
26. juni 2015 - 13:46 #8
Ref #5: Det funker !!!

Har lige 'rullet' en liste med >300.000 linier på en måde ... det tog sin tid :-(

Kan muligvis optimeres ?
26. juni 2015 - 13:47 #9
<tryltryl> Læg venligst [svar] (Ref #5) som bidrag til koden ...
Avatar billede tryltryl Juniormester
26. juni 2015 - 15:41 #10
Optimering med powershell...

kommando: powershell .\script.ps1 'data.txt' 'newdata.txt'

script.ps1:
param($source, $target)
try
{
if ([System.IO.File]::Exists($source))
{
    [regex]$re =  '^(.*?)[_ ](.*?)[_ ](.*?)[_ ](.*?)[_ ](.*)\.log'

    $sr = new-object System.IO.StreamReader($source)
    $sw = new-object System.IO.StreamWriter($target)
   
    while($sr.Peek() -ge 0)
    {
        $line = $sr.ReadLine()
        $m = $re.Match($line)
        if($m.Success)
        {
            $a = $m.Groups[1].Value
            $b = $m.Groups[2].Value
            $c = $m.Groups[3].Value
            $d = $m.Groups[4].Value
            $e = $m.Groups[5].Value
           
            $result = "{0, -20} {1, -20} {2, -15} {3, -10}" -f $e, $d, $a, $b
           
            #write-host $result
            $sw.WriteLine($result)
        }
        else
        {
            # forkert syntaks i linje. Skriv original linje til target
            $sw.WriteLine($line)
        }
    }
   
    $sr.Close()
    $sw.Close()
}
else
{
    write-host "Kunne ikke finde $source"
}
}catch
{
    write-host "Der opstod en fejl!"
    write-host $error
}
Avatar billede tryltryl Juniormester
26. juni 2015 - 18:37 #11
På min maskine med en fil på 300.000 linjer:
bat=6 min 43 sek
powershell=52sek
Avatar billede tryltryl Juniormester
26. juni 2015 - 19:45 #12
Nej, det tager 20 sek. med powershell. I C# tager det ~2 sek...

Compile til exe: csc parse.cs
Kommando: parse data.txt newdata.txt

parse.cs:
using System;
using System.IO;

class Program
{

static void Main()
{
    var args = Environment.GetCommandLineArgs();
    if(args.Length != 3)
    {
        Console.WriteLine("Forkert antal argumenter");
        return;
    }
   
    string source = args[1];
    string target = args[2];

    var re = new System.Text.RegularExpressions.Regex(@"^(.*?)[_ ](.*?)[_ ](.*?)[_ ](.*?)[_ ](.*)\.log");
    try
    {
    using(var sr = new StreamReader(source))
    {
        using(var wr = new StreamWriter(target))
        {
            while(sr.Peek() >= 0)
            {
                string line = sr.ReadLine();
                var m = re.Match(line);
                if(m.Success)
                {
                    var a = m.Groups[1].Value;
                    var b = m.Groups[2].Value;
                    var c = m.Groups[3].Value;
                    var d = m.Groups[4].Value;
                    var e = m.Groups[5].Value;
                   
                    var result = string.Format("{0,-20} {1,-20} {2,-15} {3,-10}", e, d, a, b);
                   
                    //Console.WriteLine(result);
                    wr.WriteLine(result);
                }
                else
                {
                    wr.WriteLine(line);
                }
            }
        }
    }
    }
    catch(Exception ex)
    {
        Console.WriteLine("Der opstod en fejl!");
        Console.WriteLine(ex.Message);
    }
}
}
29. juni 2015 - 09:28 #13
Set interessesant ud :-)

Skal afprøves en af dagene  !!!
21. januar 2016 - 06:54 #14
:-(

Et andet projekt har 'overhalet' denne opgave.
Som kan det ønskede på anden vis  ...

Men jeg fik da prøvet/leget med noget der  :-)

---

Implicerede parter; læg [Svar] for at lukke pænt ...
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester