Frage

Ich benutze einen Nstask, um die Ausgabe von/usr/bin/Man zu greifen. Ich bekomme die Ausgabe, aber ohne zu formatieren (fett, unterstreicht). Etwas, das so erscheinen sollte:

Fett gedruckt Text mit unterstreichen

(Beachten Sie, dass der kursive Text tatsächlich unterstrichen ist. Hier gibt es nur keine Formatierung dafür)

Stattdessen wird so zurückgegeben:

BBoolldd Text mit _u_n_d_e_r_l_i_n_e

Ich habe ein minimales Testprojekt bei http://cl.ly/052u2z2i2r280t3r1k3c dass Sie herunterladen und ausführen können; Beachten Sie, dass das Fenster nichts tut; Die Ausgabe wird an der Konsole protokolliert.

Ich nehme an, ich muss das NSDATA -Objekt irgendwie manuell interpretieren, aber ich habe keine Ahnung, wo ich damit anfangen soll. Ich würde es idealerweise gerne in einen nsattributierten String übersetzen, aber die erste Aufgabe der Geschäftsaufnahme besteht darin, die Duplikate und Unterstriche zu beseitigen. Irgendwelche Gedanken?

War es hilfreich?

Lösung

Was ist Ihr eigentlicher Zweck? Wenn Sie eine Mannseite anzeigen möchten, besteht eine Option darin, sie in HTML zu konvertieren und mit einer Webansicht zu rendern.

Parsing manDie Ausgabe kann schwierig sein, da sie von verarbeitet werden groff standardmäßig einen Terminalprozessor verwenden. Dies bedeutet, dass die Ausgabe auf Terminalgeräte angepasst wird.

Eine alternative Lösung besteht darin, den tatsächlichen Speicherort der Man -Seiten -Quelldatei zu bestimmen, z. B.

$ man -w bash
/usr/share/man/man1/bash.1.gz

und manuell aufrufen groff darauf mit -a (ASCII -Annäherung) und -c (Farbausgabe deaktivieren), z. B.

$ gunzip -c /usr/share/man/man1/bash.1.gz | groff -c -a -Tascii -man

Dies führt zu einer ASCII -Datei ohne den größten Teil der Formatierung. HTML -Ausgang zu generieren,

$ gunzip -c /usr/share/man/man1/bash.1.gz | groff -Thtml -man

Sie können diese Optionen auch in einer benutzerdefinierten Konfigurationsdatei für angeben man, zB Parseman.conf und erzählen man Verwenden Sie diese Konfigurationsdatei mit der -C Option anstatt aufzurufen man -w, gunzip, und groff. Die Standardkonfigurationsdatei ist /private/etc/man.conf.

Außerdem können Sie wahrscheinlich die Ausgabe des Terminalgeräteprozessors anpassen, indem Sie geeignete Optionen an übergeben grotty.

Andere Tipps

Okay, hier ist der Beginn meiner Lösung, obwohl ich mich für zusätzliche (einfachere?) Möglichkeiten interessieren würde, dies zu tun.

Die aus dem Terminal zurückgegebene Ausgabe ist die UTF-8-Codierung, aber das NSUTF8StringCoding interpretiert die Zeichenfolge nicht ordnungsgemäß. Der Grund ist die Art und Weise, wie die Ausgabe des Nstasks formatiert wird.

Der Buchstabe N ist 0x4e in UTF-8. Aber die nsdata entspricht 0x4e 0x08 0x4e. 0x08 entspricht einem Rückraum. Für einen mutigen Buchstaben druckt Terminal-Buchstaben-Backspace-Buchstaben.

Für ein kursives C ist es 0x63 in UTF-8. Die NSDATA enthält 0x5f 0x08 0x63, wobei 0x5f einem Unterstrich entspricht. Für Kursivschrift unterstreichen Terminaldrucke unterstreichend.

Ich sehe an diesem Punkt wirklich nicht so, als nur die rohe NSData nach diesen Sequenzen zu scannen. Ich werde die Quelle wahrscheinlich hier für meinen Parser veröffentlichen, sobald ich sie beendet habe, es sei denn, jemand hat vorhandenen Code. Schreiben Sie sich niemals selbst, was Sie kopieren können. :)

Nachverfolgen:

Ich habe einen guten, schnellen Parser zusammen, um die Mannausgabe zu nehmen und die fett gedruckte/unterstrichene Ausgabe durch fett gedruckte/unterstrichene Formatierung in einem nsmutableAttributString zu ersetzen. Hier ist der Code, wenn jemand anderes das gleiche Problem lösen muss:

NSMutableIndexSet *boldChars = [[NSMutableIndexSet alloc] init];
NSMutableIndexSet *underlineChars = [[NSMutableIndexSet alloc] init];

char* bBytes = malloc(1);
bBytes[0] = (char)0x08;
NSData *bData = [NSData dataWithBytes:bBytes length:1];
free(bBytes); bBytes = nil;
NSRange testRange = NSMakeRange(1, [inputData length] - 1);
NSRange bRange = NSMakeRange(0, 0);

do {
    bRange = [inputData rangeOfData:bData options:(NSDataSearchOptions)NULL range:testRange];
    if (bRange.location == NSNotFound || bRange.location > [inputData length] - 2) break;
    const char * buff = [inputData bytes];

    if (buff[bRange.location - 1] == 0x5f) {

        // it's an underline
        //NSLog(@"Undr %c\n", buff[bRange.location + 1]);
        [inputData replaceBytesInRange:NSMakeRange(bRange.location - 1, 2) withBytes:NULL length:0];
        [underlineChars addIndex:bRange.location - 1];
        testRange = NSMakeRange(bRange.location, [inputData length] - (bRange.location));

    } else if (buff[bRange.location - 1] == buff[bRange.location + 1]) {

        // It's a bold
        //NSLog(@"Bold %c\n", buff[bRange.location + 1]);
        [inputData replaceBytesInRange:NSMakeRange(bRange.location - 1, 2) withBytes:NULL length:0];
        [boldChars addIndex:bRange.location - 1];
        testRange = NSMakeRange(bRange.location, [inputData length] - (bRange.location));

    } else {

        testRange.location = bRange.location + 1;
        testRange.length = [inputData length] - testRange.location;
    }
} while (testRange.location <= [inputData length] - 3);

NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:[[NSString alloc] initWithData:inputData encoding:NSUTF8StringEncoding]];

NSFont *font = [NSFont fontWithDescriptor:[NSFontDescriptor fontDescriptorWithName:@"Menlo" size:12] size:12];
NSFont *boldFont = [[NSFontManager sharedFontManager] convertFont:font toHaveTrait:NSBoldFontMask];

[str addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, [str length])];

__block NSUInteger begin = [underlineChars firstIndex];
__block NSUInteger end = begin;
[underlineChars enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
    if (idx - end < 2) {
        // it's the next item to the previous one
        end = idx;
    } else {
        // it's a split, so drop in the accumulated range and reset
        [str addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInt:NSSingleUnderlineStyle] range:NSMakeRange(begin, (end-begin)+1)];
        begin = idx;
        end = begin;
    }
    if (idx == [underlineChars lastIndex]) {
        [str addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInt:NSSingleUnderlineStyle] range:NSMakeRange(begin, (end-begin)+1)];
    }
}];

begin = [boldChars firstIndex];
end = begin;
[boldChars enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
    if (idx - end < 2) {
        // it's the next item to the previous one
        end = idx;
    } else {
        // it's a split, so drop in the accumulated range and reset
        [str addAttribute:NSFontAttributeName value:boldFont range:NSMakeRange(begin, (end-begin)+1)];
        begin = idx;
        end = begin;
    }
    if (idx == [underlineChars lastIndex]) {
        [str addAttribute:NSFontAttributeName value:boldFont range:NSMakeRange(begin, (end-begin)+1)];
    }
}];

Eine andere Methode besteht darin, die Mannseite in den PostScript-Quellcode umzuwandeln, diesen über den PostScript-to-PDF-Konverter auszuführen und dies in eine PDFView zu setzen.

Die Implementierung wäre ähnlich wie die Antwort von Bavarious, nur mit unterschiedlichen Argumenten zum Maschen (-Tps Anstatt von -Thtml).

Dies wäre die langsamste Lösung, aber wahrscheinlich auch die beste zum Drucken.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top