ubuntuusers.de

C und reguläre Ausdrücke (regexec())

Status: Gelöst | Ubuntu-Version: Ubuntu 10.04 (Lucid Lynx)
Antworten |

Dakuan

Avatar von Dakuan

Anmeldungsdatum:
2. November 2004

Beiträge: 6488

Wohnort: Hamburg

In meinem letzten Programmprojekt musste ich wegen komplexer Textvergleiche auf die Bibiotheksfunktion regexec() zurückgreifen. Im Prinzip funktioniert das auch überaschend gut, und ich frage mich warum ich das nicht schon früher gemacht habe.

Aber ein kleines Problem gibt es da noch. Es handelt sich dabei um einen Katalog von Metataten von Bilddateien (Beschreibungen). Ich möche jetzt nach allen Datensätzen suchen, die eine Zeilenwechsel enthalten. Nach Wikipedia sollte das mit '\n' möglich sein, aber ich bekomme dann alle Datensätze, die den Buchstaben 'n' enthalten.

Ich habe bisher keine besonderen Flags angegeben und es werden auch Suchbegriffe gefunden, die sich in der zweiten oder dritten Zeile des Datzensatzes befinden.

Ist es mit dieser Funktion überhaupt möglich einen Zeilenwechsel zu suchen?

p.s. Ich weiss, das der Zeilenwechsel definitiv vorhanden ist, denn im Debug Modus kann ich die Datensätze zusätzlich als HexDump ausgeben, und da ist dann jedes Bit sichtbar. Nur selektieren kann ich die nicht.

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Je nachdem, wie Du den Text eingibst, ist da vielleicht ein doppelter Rückstrich nötig ? - also \\n ?

So ist das jedenfalls bei Shellskripten, bei C weiß ich es nicht. Du kannst es ja einfach mal probieren.

LG,

track

Dakuan

(Themenstarter)
Avatar von Dakuan

Anmeldungsdatum:
2. November 2004

Beiträge: 6488

Wohnort: Hamburg

Das funktioniert leider auch nicht. Das die Bash da immer versucht etwas zu verändern, habe ich bei einigen Suchmustern auch schon bemerkt. Ich gebe die dann imme in einfachen Anführungszeichen ' ein. Ich habe mir jetzt auch schon die Suchmuster wieder ausgeben lassen, um sicher zu gehen, das da nichts verloren gegangen ist.

Aber selbst wenn ich erweiterte reguläre Ausdrücke (Flag: REG_EXTENDED) verwende geht es nicht. Und das scheint auch einige andere Zeichenfolgen die mit "\" beginnen zu betreffen. Fehlermeldungen gibt es dabei keine. Es scheint fast so, als wenn das in der Linux Version nicht vorgesehen ist oder generell anders eingegeben werden muss.

tischbein

Avatar von tischbein

Anmeldungsdatum:
21. Juli 2008

Beiträge: 404

Dakuan schrieb:

Aber selbst wenn ich erweiterte reguläre Ausdrücke (Flag: REG_EXTENDED) verwende geht es nicht. Und das scheint auch einige andere Zeichenfolgen die mit "\" beginnen zu betreffen. Fehlermeldungen gibt es dabei keine. Es scheint fast so, als wenn das in der Linux Version nicht vorgesehen ist oder generell anders eingegeben werden muss.

Nee, vorgesehen ist das schon 😉 Du musst aber bedenken, dass <regex.h> kein PCRE versteht, sondern sogenannte POSIX RegExp verwendet, und da sind die matching-regel anders.
Als anfang, kannst du ja mal den ausdruck posten, den du verwendest.

Dakuan

(Themenstarter)
Avatar von Dakuan

Anmeldungsdatum:
2. November 2004

Beiträge: 6488

Wohnort: Hamburg

Ich hatte immer direkt

\n

verwendet. Da wird dann alles gefunden, wo ein n drinne vorkommt. Ich habe jetzt festgestellt, das einige Quantoren auch nicht bzw. nur mit REG_EXTENDED gehen. z.B. "o+" findet nichts, weil kein "+" vorkommt.

barcc

Avatar von barcc

Anmeldungsdatum:
13. Juli 2007

Beiträge: 696

Wohnort: Dortmund

Vielleicht könntest du uns etwas mehr von deinem Programm zeigen? "\n" wird schon vom C-Compiler in einen Zeilenumbruch übersetzt, wie soll das dann auf "n" matchen wie du behauptest?

Dakuan

(Themenstarter)
Avatar von Dakuan

Anmeldungsdatum:
2. November 2004

Beiträge: 6488

Wohnort: Hamburg

Vielleicht könntest du uns etwas mehr von deinem Programm zeigen?

Der gesamte Programmcode ist inzwischen fast 700 Zeilen lang. Wenn ich da hier komplett hochladen darf? Aber das ist eigentlich nur verständlich, wenn man auch die zu untersuchende Datei hat und derren Binärformat kennt. Wobei der Code noch einige ungelöste Baustellen enthält, die aber nur die logische Kombination mehrerer Suchergebnisse betreffen, also eigentlich in den Kosmetikbereich gehören.

Also eine typische Abfrage für das dritte Datenfeld eines Datensatzes könnte z.B. so aussehen:

sdb -i 3:root

Das wird dann für jede Eingabe abgearbeitet mit:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
int
get_pattern( char * p, Src_Data * sdptr )
{
    int m, n;

    sdptr->mode = 1;
    if( isdigit( *p )  &&  *(p + 1) == ':' ) {
        n = atoi( p );
        switch( n ) {
            case 2:     m = 2;  break;
            case 3:     m = 4;  break;
            case 4:     m = 8;  break;
            default:    m = 1;
        }
	sdptr->mask = m;
        p += 2;
    }
    sdptr->pat = p;
    return 1;
}

ob das so auch angekommen ist zeigt mir die markierte Zeile in:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
    /* restlich Kommandoz. Parameter verarbeiten */
    i = 0;
    sdat_cnt = 0;
    sdptr = sdat;
    while( optind < argc  &&  sdat_cnt < SDAT_NUM ){
        sdptr->mask = o_field_mask;
        sdptr->mode = 1;
        sdptr->flg = reg_flags;
        get_pattern( argv[ optind ], sdptr );
printf( " > Suchmuster %d: %s\n", sdat_cnt, sdptr->pat ); /* <<<<<<<<<<<<<<<<<<<<<<<<*/
        if( regcomp( &sdptr->regex, sdptr->pat, sdptr->flg ) ) {
            fprintf( stderr, "Error in expression '%s'\n", sdptr->pat );
            exit( 7 );
        }
        optind++;
        sdptr++;
        sdat_cnt++;
    }

Die Markierte Zeile sollte meiner Meinung nach genau das zeigen, was dann auch tatsächlich für die Suchmaske ausgewertet wird.

barcc

Avatar von barcc

Anmeldungsdatum:
13. Juli 2007

Beiträge: 696

Wohnort: Dortmund

Ok, du übergibst das Suchmuster also über die Kommandozeile. Ich rate jetzt mal das du ungefähr so etwas machst:

./program '\n'

und dann in der Ausgabe so etwas auftaucht:

> Suchmuster 1: \n

Das ist dann aber kein Zeilenumbruch, sondern zwei Zeichen, ein Backslash und ein kleines n. Stattdessen musst du folgendes machen:

./program '
'

und in der Ausgabe siehst du dann:

> Suchmuster 1: 

Damit sollte dein Programm dann Zeilenumbrüche statt n finden.

snafu1

Avatar von snafu1

Anmeldungsdatum:
5. September 2007

Beiträge: 2133

Wohnort: Gelsenkirchen

Oder alternativ:

1
./dein_programm $'\n'

Dies funktioniert mindestens mit den Shells bash und zsh.

Dakuan

(Themenstarter)
Avatar von Dakuan

Anmeldungsdatum:
2. November 2004

Beiträge: 6488

Wohnort: Hamburg

Danke, jetzt funktioniert es!

Ich bin immer davon ausgagangen, das die Zeichenfolge von regcomp() interpretiert werden muss. Daher bin ich nicht auf die Idee gekommen, das man die Shell dazu bringen muss das \n Zeichen selbst zu senden. Und dabei steht in der Beschreibung, das ein Zeilenwechsel wie ein normales Zeichen behandelt wird, sofern keine besonderen Flags gesetzt sind...

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Dakuan schrieb:

Und dabei steht in der Beschreibung, das ein Zeilenwechsel wie ein normales Zeichen behandelt wird, sofern keine besonderen Flags gesetzt sind...

Stimmt ja auch ! - nur wenn Du ihm per Konsole die Zeichenfolge "\n" schickst, kommt dazwischen halt niemand mehr, der das interpretieren würde.

track

Antworten |