Toon posts:

[C /C++] bytes vervangen in een textfile

Pagina: 1
Acties:

Verwijderd

Topicstarter
Hallo,

Ik ben bezig met een klein C++ projectje maar dat wil niet echt vlotten.
De laatste keer dat ik C++ progammeerde was ook alweer 4 jaar geleden ;)
Roestig kunnen we dus rustig zeggen.

Wat wil ik doen: Ik heb een tekst file en daar wil ik een set tekens omzetten naar 1 character.
Het zijn de decimale karakters : 10, 13 en 13. Als ik die in een rij tegenkom wil ik ze omzetten
dat ik alleen 10 wegschrijf.

Ik heb het volgende al:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <stdio.h>
#include <windows.h>

FILE *InputFile;            // Variable for Input File
FILE *OutputFile;           // Variable for Output File
byte *iobyte;               // Byte to read and write
unsigned short nbRead = 0;  // Returns the number of byte (read)
unsigned short nbWrite = 0; // Returns the number of byte (write)

void main (int argc, unsigned char **argv)
{

    if(argc < 3)
    {
        return;
    }

    // Memory allocation
    iobyte = (byte *)malloc(1);

    // Open the input file (1st parameter)
    if( (InputFile = fopen((const char *)argv[1], "rb")) == NULL)
    {
        return;
    }
    
    // Open the output file (2nd parameter)
    if( (OutputFile = fopen((const char *)argv[2], "w+b")) == NULL)
    {
        fclose(InputFile);
        return;
    }

    nbRead = fread(iobyte, 1, 1, InputFile);
    while (nbRead == 1)
    {
        // Are the next 3 bytes 0A0D0D ? (10,13,13)
        if (*iobyte == 10 && (*iobyte + 1) == 13 && (*iobyte + 2) == 13)
        {
            // Write linefeed
            nbWrite = fwrite(&("\x0A"), 1, 1, OutputFile);
            // Read third byte
            nbRead = fread(iobyte, 1, 3, InputFile);
        }
        else
        {
            // Write 1 byte
            nbWrite = fwrite(iobyte, 1, 1, OutputFile);
            // Read next byte
            nbRead = fread(iobyte, 1, 1, InputFile);
        }       
    }


    // Close input and output files and free memory
    fclose(InputFile);
    fclose(OutputFile);
    free(iobyte);
    return;
}


Zoals je wellicht kan zien is de regel
code:
1
if (*iobyte == 10 && (*iobyte + 1) == 13 && (*iobyte + 2) == 13)

niet helemaal juist, maar dat is waarschijnlijk omdat er maar steeds 1 byte wordt ingelezen op dit moment.... :?
Kan iemand mij een schop in de juiste richting geven?
Alvast bedankt! :)

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Als je 1 byte nodig hebt is de stack een veel beter idee. Heel veel beter zelfs.

De nette oplossing is natuurlijk de hele file lezen, vervolgens in het geheugen een replace te doen, en alles terugschrijven. Deze aanpak is onacceptabel slordig.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • joca
  • Registratie: Oktober 2000
  • Laatst online: 12-07-2025
Probeer eens:


code:
1
if (*iobyte == 10 && *(iobyte + 1) == 13 && *(iobyte + 2) == 13)


In jouw code verhoog je de inhoud van je orginele pointer(waar hij dus heen wijst). Met bovenstaande verhoog je eerst het adres.

Verwijderd

Topicstarter
In jouw code verhoog je de inhoud van je orginele pointer(waar hij dus heen wijst). Met bovenstaande verhoog je eerst het adres.
Het is natuurlijk wel zo dat hij het bestand byte voor byte inleest. Dus volgens mij gaat dit uberhaupt niet werken. bytes vervangen door een andere byte is dit geschikte code...
edit:

net getest, en werkt inderdaad niet :| iig bedankt


Ik denk dat MSalters gelijk heeft en ik het hele bestand in het geheugen moet laden, daar de replace moet uitvoeren en dan weer wegschrijven.

*zucht* Nah ja ik ga uitzoeken hoe dat dan weer te doen :)

[ Voor 7% gewijzigd door Verwijderd op 29-06-2005 14:26 ]


  • Amotea
  • Registratie: Mei 2004
  • Laatst online: 23-01-2025
Ik heb toevallig net een soortgelijk iets gemaakt. Hierbij was snelheid geboden en heb ik dus voor wat meer ruwe en waarschijnlijk foutgevoelige code gekozen. Ook ging het hier om binary data ipv. gewone tekst. Maar dat maakt het niet heel verschillend.

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <fstream>

const char* input_filename = "input.txt";
const char* output_filename = "output.txt";

    // declarations
    char* input_buffer;
    char* output_buffer;
    long input_size;

    // open files
    std::ifstream input_file(input_filename, std::ios::in|std::ios::binary|std::ios::ate);
    std::ofstream output_file(output_filename, std::ios::out|std::ios::binary);

    input_size = input_file.tellg();
    input_file.seekg (0, std::ios::beg);
    input_buffer = new char[input_size];
    input_file.read (input_buffer, input_size);
    input_file.close();

    output_buffer = new char[input_size];

/* voer hier je bewerkingen uit op de array, en zorg dat het resultaat van deze bewerkingen in output_buffer komt */

    output_file.write(output_buffer, input_size);
    output_file.close();

    // clean up
    delete[] input_buffer;
    delete[] output_buffer;

Zorg dat je dus ook nog even de access mode verandert naar text.

[ Voor 3% gewijzigd door Amotea op 29-06-2005 16:18 . Reden: Even de benodigde headerfile erbij gezet. ]


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Zelf kwam ik op dit:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
template <typename OutIt>
class StripCR : public std::unary_function<char, void> {
    OutIt oi_;
    bool seen;
public:
    explicit StripCR(OutIt oi) : oi_(oi), seen(false) {}
    ~StripCR() {}

    void operator()(char c) {
        if (c == 10) {
            if (!seen) {
                *oi_ = '\13';
                ++oi_;
            }
        } else {
            *oi_ = c;
            ++oi_;
        }
        seen = (c == 13);
    }
};

void stripFile(std::istream& is, std::ostream& os) {
    std::for_each(
        std::istreambuf_iterator<char>(is), 
        std::istreambuf_iterator<char>(),
        StripCR<std::ostreambuf_iterator<char> >(std::ostreambuf_iterator<char>(os))
    );
}


int main() {
    std::ifstream ifs("input.txt", std::ios::in | std::ios::binary);
    std::ofstream ofs("output.txt", std::ios::out | std::ios::binary);

    stripFile(ifs, ofs);
    return 0;
}


(op dit soort momenten is perl toch wel weer handig...)
Perl:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/perl
#
# Simple script to strip carriage returns from text files

foreach $file (@ARGV) {
    $file2 = "$file.nocr";
    open(IN,$file) || die "Can't open $file for reading!\n";
    open(OUT,">$file2") || die "Can't open $file2 for writing!\n";
    while(<IN>) {
        s/\015//g;
        print OUT;
    }
    close(IN);
    close(OUT);
    unlink($file);
    rename($file2,$file);
}

[ Voor 46% gewijzigd door Zoijar op 29-06-2005 18:12 . Reden: iets algemenere versie ]


  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

ik heb dit reeds een tijd geleden geschreven en wil je dan ook volledig gratis de code aangeven ;)

http://users.pandora.be/lucdevriendt/Convert.cpp

dit programmaatje compileer met een verschillende main afhankelijk van het OS waarop het gecompileerd wordt (maw je convert altijd van het vreemd OS naar het OS waarop je compileert)

het is niet DE beste versie, maar het werkt, en goed...
bovendien kan ik je ook Notepad++ aanbevelen indien het om tekst bestandjes gaat... dit programma is, bovenop een prima editor voor 1001 bestandjes ook een handige harry wat encoderingen betreft en schakelt snel om van Windows/*NIX/Mac etc...

ASSUME makes an ASS out of U and ME


  • Coca-Cola
  • Registratie: Maart 2001
  • Laatst online: 14:33
Zoijar schreef op woensdag 29 juni 2005 @ 17:16:
ontzettend mooie code..
[/code]
Haha dat vind ik nou mooi, ik dacht dat ik wel een beetje kon proggen, maar dit soort code schud ik dus echt niet zomaar even uit mijn mouw, heel netjes Zoijar!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Zoijar schreef op woensdag 29 juni 2005 @ 17:16:
Zelf kwam ik op dit:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
template <typename OutIt>
class StripCR : public std::unary_function<char, void> {
    OutIt oi_;
    bool seen;
public:
    explicit StripCR(OutIt oi) : oi_(oi), seen(false) {}
    ~StripCR() {}

    void operator()(char c) {
        if (c == 10) {
            if (!seen) {
                *oi_ = '\13';
                ++oi_;
            }
        } else {
            *oi_ = c;
            ++oi_;
        }
        seen = (c == 13);
    }
};

void stripFile(std::istream& is, std::ostream& os) {
    std::for_each(
        std::istreambuf_iterator<char>(is), 
        std::istreambuf_iterator<char>(),
        StripCR<std::ostreambuf_iterator<char> >(std::ostreambuf_iterator<char>(os))
    );
}


int main() {
    std::ifstream ifs("input.txt", std::ios::in | std::ios::binary);
    std::ofstream ofs("output.txt", std::ios::out | std::ios::binary);

    stripFile(ifs, ofs);
    return 0;
}
Waarom geen remove_copy? Met boost::bind kun je het predicaat waarschijnlijk in-place schrijven :Y)

even schetsen:
C++:
1
2
3
4
5
6
7
8
9
void stripFile(std::istream& is, std::ostream& os) {
    bool seen;
    std::remove_copy(
        std::istreambuf_iterator<char>(is), 
        std::istreambuf_iterator<char>(),
        std::ostreambuf_iterator<char>(os),
        ( boost::ref(seen)== 13 && (boost::ref(seen)=_1) && _1 ==10 )
    );
}

Ja, na de eerste && komt een assignment die altijd true is. Subtiel, niet? Ga het niet compileren, dat kan alleen tegenvallen.

[ Voor 28% gewijzigd door MSalters op 30-06-2005 15:51 ]

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Omdat STL predicate functors geen side-effects (of state) mogen hebben. Ik zal zo even naar je code kijken, ik moet nu snel weg...

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Geen side effects op de range. (para 25/7)

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Verwijderd

Coca-Cola schreef op donderdag 30 juni 2005 @ 14:33:
[...]

Haha dat vind ik nou mooi, ik dacht dat ik wel een beetje kon proggen, maar dit soort code schud ik dus echt niet zomaar even uit mijn mouw, heel netjes Zoijar!
Nou nou, beetje overdreven ;) De code is absoluut mooi, maar eigenlijk is (zou!) dit gewoon een standaard practice (moeten zijn). Itereren over een collection via een for_each waarbij voor elke element een meegegeven functie wordt aangeroepen.

Tevens, de mogelijkheid om direct lambda functies te maken in C++ via een omweg laat zien hoe krachtig C++ is. Het zou echter toch leuker zijn als er direct support voor zoiets was, zodat je voor een lambda functie gewoon de normale syntax kon gebruiken. Nu zien if/else construcies er wel erg gekunsteld uit. Voor de echter liefhebber is het wel kewl natuurlijk :)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 05-05 18:07

.oisyn

Moderator Devschuur®

Demotivational Speaker

MSalters schreef op donderdag 30 juni 2005 @ 15:43:
C++:
1
( boost::ref(seen)== 13 && (boost::ref(seen)=_1) && _1 ==10 ) 
Ik ben een beetje confuus hoe dit gaat werken. Je compared ten eerste een bool tegen 13, maar ik vermoed dat je char bedoelde ipv bool. Maar mijn punt is meer dat 'seen' pas reassigned wordt als seen gelijk is aan 13, en als dat niet het geval is zal de expressie altijd false opleveren.

Bedoel je niet:
C++:
1
(boost::ref(seen) && _1 == 13 || ((boost::ref(seen) = (_1 == 10)) && 0)


als eerst wordt seen && _1 == 13 geevalueerd. Als seen true is en _1 gelijk aan 13, dan wordt hij geremoved. Als _1 ongelijk is aan 13 is het false waardoor _1 geoutput wordt. Als seen false is, wordt seen geassigned met de expressie (_1 == 10), en door de && 0 op het eind zal de totale expressie dan false zijn zodat de 10 zelf niet geremoved wordt.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

MSalters schreef op donderdag 30 juni 2005 @ 17:48:
Geen side effects op de range. (para 25/7)
Hmm ik doelde op dit soort code: (standaard voorbeeld)
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class P : public std::unary_function<int, bool> {
public:
    P() : n_(0) {}
    bool operator()(int i) { // wis 2e element
        return ++n_ == 2;
    }
private:
    int n_;
};

int main() {
    const int ar[] = {1,2,3,4,5,6,7,8,9};
    std::vector<int> v(&ar[0], &ar[sizeof(ar)/sizeof(int)]);

    copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << std::endl;
    v.erase(remove_if(v.begin(), v.end(), P()), v.end());
    copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
    return 0;
}

Dit wist het 2e element, maar ook (op mijnSTL implementatie) het 4e. Dit komt omdat er twee algoritmes samenwerken, maar op verschillende kopieen van het predicate object P() [edit]hiermee bedoel ik niet remove_if en erase, maar binnen de implementatie van remove_if; meestal find_if en remove_if zelf). En er zijn hier ook geen side effects op de range, maar het predicate heeft wel state. Heb ik iets verkeerd begrepen? Ik heb het even getest met een 'seen' bool, en een remove_copy_if, en dat lijkt wel te werken... Ik heb altijd gedacht dat je enkel state mag bijhouden met for_each, aangezien for_each ook weer je functie object returned na uitvoering (ok, en accumulate dan, en ik neem aan die lopende som en verschil dingen.)

offtopic:
De eis was volgens mij ook dat bij een 13 gevolgd door een 10 de 10 erased moest worden, en dat bij een losse 10 de 10 door een 13 vervangen moest worden. Dan moet je na de remove_copy nog een replace doen.
Coca-Cola schreef op donderdag 30 juni 2005 @ 14:33:
Haha dat vind ik nou mooi, ik dacht dat ik wel een beetje kon proggen, maar dit soort code schud ik dus echt niet zomaar even uit mijn mouw, heel netjes Zoijar!
Thnx :) Het valt mee hoor, lijkt meer dan het is...C++ met STL/streams en templates kost alleen wat tijd/moeite tot je het goed leest/schrijft.

[ Voor 6% gewijzigd door Zoijar op 30-06-2005 19:05 ]


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
.oisyn schreef op donderdag 30 juni 2005 @ 18:41:
[...]
Ik ben een beetje confuus hoe dit gaat werken. Je compared ten eerste een bool tegen 13, maar ik vermoed dat je char bedoelde ipv bool. Maar mijn punt is meer dat 'seen' pas reassigned wordt als seen gelijk is aan 13, en als dat niet het geval is zal de expressie altijd false opleveren.

Bedoel je niet:
C++:
1
(boost::ref(seen) && _1 == 13 || ((boost::ref(seen) = (_1 == 10)) && 0)
Ongetwijfeld. Ik had er geen smiley ondergezet, maar dit soort code schrijf je natuurlijk niet
als een lamda-expressie. Ik heb er dus ook niet al te hard over nagedacht. Zoijar's oplossing met een losse functor is natuurlijk beter; mijn echte punt was dat je met remove_copy een simpele functor hebt.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Zoijar schreef op donderdag 30 juni 2005 @ 18:50:
[...]

Hmm ik doelde op dit soort code: (standaard voorbeeld)
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class P : public std::unary_function<int, bool> {
public:
    P() : n_(0) {}
    bool operator()(int i) { // wis 2e element
        return ++n_ == 2;
    }
private:
    int n_;
};

int main() {
    const int ar[] = {1,2,3,4,5,6,7,8,9};
    std::vector<int> v(&ar[0], &ar[sizeof(ar)/sizeof(int)]);

    copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << std::endl;
    v.erase(remove_if(v.begin(), v.end(), P()), v.end());
    copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
    return 0;
}

Dit wist het 2e element, maar ook (op mijnSTL implementatie) het 4e. Dit komt omdat er twee algoritmes samenwerken, maar op verschillende kopieen van het predicate object P()
Er zijn genoeg dingen in C++ die mogen en toch onverwachte resultaten opleveren. :Y)

[ Voor 5% gewijzigd door MSalters op 01-07-2005 10:14 ]

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

MSalters schreef op vrijdag 01 juli 2005 @ 10:14:
Er zijn genoeg dingen in C++ die mogen en toch onverwachte resultaten opleveren. :Y)
Ok :) Maar als men dus nog lang ergens wilt werken, kan men beter geen state bijhouden in predicates :+
Pagina: 1