web-dev-qa-db-de.com

Wie drucke ich Sonderzeichen explizit in C?

Wenn ich folgenden Code verwende:

#include <stdio.h>

int main(void)
{
    printf("%s","Hello world\nHello world");
    return 0;
}

es druckt als:

 Hello world
 Hello world

Wie kann ich das verhindern und als unformatiertes String-Literal in C ausgeben? Ich meine, es sollte angezeigt werden, wie es im Terminalfenster wie folgt ist:

Hello world\nHello world

Ich weiß, dass ich dies mit Backslash für printf erreichen kann, aber gibt es eine andere C-Funktion oder einen anderen Weg, dies ohne Backslash zu tun? Es wäre hilfreich beim Lesen von Dateien.

8
Jessie

Dafür gibt es keinen eingebauten Mechanismus. Sie müssen es manuell tun, Zeichen für Zeichen. Die Funktionen in ctype.h können jedoch hilfreich sein. Insbesondere in der Ländereinstellung "C" ist die Funktion isprint für alle Grafikzeichen im Basisausführungszeichensatz garantiert wahr, was praktisch mit allen Grafikzeichen in 7-Bit identisch ist ASCII plus Leerzeichen; und es ist garantiert, dass nicht für alle control -Zeichen in 7-Bit-ASCII zutreffend ist, einschließlich Tabulatorzeichen, Wagenrücklauf usw.

Hier ist eine Skizze:

#include <stdio.h>
#include <ctype.h>
#include <locale.h>

int main(void)
{
    int x;
    setlocale(LC_ALL, "C"); // (1)

    while ((x = getchar()) != EOF)
    {
        unsigned int c = (unsigned int)(unsigned char)x; // (2)

        if (isprint(c) && c != '\\')
            putchar(c);
        else
            printf("\\x%02x", c);
    }
    return 0;
}

Dies entgeht weder ' noch ", sondern \ und es ist unkompliziert, dies zu erweitern, wenn Sie es brauchen.

Das Drucken von \n für U + 000A, \r für U + 000D usw. bleibt als Übung bestehen. Der Umgang mit Zeichen außerhalb des grundlegenden Ausführungszeichensatzes (z. B. UTF-8-Kodierung von U + 0080 bis U + 10FFFF) wird ebenfalls als Übung gelassen.

Dieses Programm enthält zwei Dinge, die für eine vollständig standardkonforme C-Bibliothek nicht erforderlich sind, aber nach meiner Erfahrung auf realen Betriebssystemen erforderlich waren. Sie sind mit (1) und (2) gekennzeichnet.

1) Hiermit wird die "locale" -Konfiguration explizit so festgelegt, wie sie ist vermutlich .

2) Der von getchar zurückgegebene Wert ist eine int. Es ist angenommen entweder eine Zahl in dem durch unsigned char darstellbaren Bereich (normalerweise 0-255 einschließlich) oder der spezielle Wert EOF (der nicht in dem durch unsigned char darstellbaren Bereich ist) . Es ist jedoch bekannt, dass fehlerhafte C-Bibliotheken negative Zahlen für Zeichen mit dem höchsten gesetzten Bit zurückgeben. In diesem Fall druckt die printf (zum Beispiel) \xffffffa1, wenn \xa1 gedruckt werden soll. Das Umwandeln von x in unsigned char und dann wieder von unsigned int korrigiert dies.

5
zwol

So etwas könnte das sein, was Sie wollen. Führen Sie myprint(c) aus, um das Zeichen C oder eine druckbare Darstellung davon zu drucken:

#include <ctype.h>

void myprint(int c)
{
    if (isprint(c))
        putchar(c); // just print printable characters
    else if (c == '\n')
        printf("\\n"); // display newline as \n
    else
        printf("%02x", c); // print everything else as a number
}

Wenn Sie Windows verwenden, denke ich, dass alle Ihre Zeilenumbrüche CRLF (Wagenrücklauf, Zeilenvorschub) sind, so dass sie als 0d\n so gedruckt werden, wie ich diese Funktion geschrieben habe.

1
yellowantphil

Wenn ich die Frage verstehe, wenn Sie eine Zeichenfolge mit Steuerzeichen wie Zeilenumbruch, Tabulator, Rücktaste usw. haben, möchten Sie eine Textdarstellung dieser Zeichen drucken, anstatt sie als Steuerzeichen zu interpretieren. 

Leider gibt es keinen integrierten printf-Konvertierungsspezifizierer, der dies für Sie tun wird. Sie müssen die Zeichenfolge Zeichen für Zeichen durchgehen, jeden testen, um zu sehen, ob es sich um ein Steuerzeichen handelt, und einen entsprechenden Text schreiben.

Hier ist ein schnelles, leicht getestetes Beispiel:

#include <stdio.h>
#include <limits.h>
#include <ctype.h>
...
char *src="This\nis\ta\btest";

char *lut[CHAR_MAX] = {0};  // look up table for printable equivalents
                            // of non-printable characters
lut['\n'] = "\\n";
lut['\t'] = "\\t";
lut['\b'] = "\\b";
...
for ( char *p = src; *p != 0; p++ )
{
  if ( isprint( *p ) )
    putchar( *p );
  else
    fputs( lut[ (int) *p], stdout ); // puts adds a newline at the end,
                                     // fputs does not.
}
putchar( '\n' );
0
John Bode

Vielen Dank an den Benutzer@chunkfür die Verbesserung dieser Antwort.


Warum haben Sie keine Allzwecklösung geschrieben? Es würde Sie in Zukunft von vielen Problemen abhalten.

char *
str_escape(char str[])
{
    char chr[3];
    char *buffer = malloc(sizeof(char));
    unsigned int len = 1, blk_size;

    while (*str != '\0') {
        blk_size = 2;
        switch (*str) {
            case '\n':
                strcpy(chr, "\\n");
                break;
            case '\t':
                strcpy(chr, "\\t");
                break;
            case '\v':
                strcpy(chr, "\\v");
                break;
            case '\f':
                strcpy(chr, "\\f");
                break;
            case '\a':
                strcpy(chr, "\\a");
                break;
            case '\b':
                strcpy(chr, "\\b");
                break;
            case '\r':
                strcpy(chr, "\\r");
                break;
            default:
                sprintf(chr, "%c", *str);
                blk_size = 1;
                break;
        }
        len += blk_size;
        buffer = realloc(buffer, len * sizeof(char));
        strcat(buffer, chr);
        ++str;
    }
    return buffer;
}

Wie es funktioniert!

int
main(const int argc, const char *argv[])
{
    puts(str_escape("\tAnbms\n"));
    puts(str_escape("\tA\v\fZ\a"));
    puts(str_escape("txt \t\n\r\f\a\v 1 \t\n\r\f\a\v tt"));
    puts(str_escape("dhsjdsdjhs hjd hjds "));
    puts(str_escape(""));
    puts(str_escape("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&\'()*+,-./:;<=>[email protected][\\]^_`{|}~ \t\n\r\f\a\v"));
    puts(str_escape("\x0b\x0c\t\n\r\f\a\v"));
    puts(str_escape("\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14"));
}

Ausgabe

\tAnbms\n
\tA\v\fZ\a
txt \t\n\r\f\a\v 1 \t\n\r\f\a\v tt
dhsjdsdjhs hjd hjds 

0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&'()*+,-./:;<=>[email protected][\]^_`{|}~ \t\n\r\f\a\v
\v\f\t\n\r\f\a\v
\a\b\t\n\v\f\r

Diese Lösung basiert auf Informationen aus der Wikipedia https://en.wikipedia.org/wiki/Escape_sequences_in_C#Table_of_escape_sequences Und den Antworten anderer Benutzer von stackoverflow.com.


Testumgebung

$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 8.6 (jessie)
Release:    8.6
Codename:   jessie
$ uname -a
Linux localhost 3.16.0-4-AMD64 #1 SMP Debian 3.16.36-1+deb8u2 (2016-10-19) x86_64 GNU/Linux
$ gcc --version
gcc (Debian 4.9.2-10) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
0
Seti Volkylany