1

/usr/bin/man からの出力を取得するために NSTask を使用しています。出力を取得していますが、書式設定 (太字、下線) はありません。次のように表示されます。

下線付きの太字テキスト

(イタリック体のテキストには実際に下線が引かれていることに注意してください。ここでは書式はありません)

代わりに、次のように返されます。

_u_n_d_e_r_l_i_n_e の BBoolldd テキスト

ダウンロードして実行できるhttp://cl.ly/052u2z2i2R280T3r1K3cに最小限のテスト プロジェクトがあります。ウィンドウは何もしないことに注意してください。出力はコンソールに記録されます。

何らかの形で NSData オブジェクトを手動で解釈する必要があると思いますが、どこから始めればよいかわかりません。理想的にはそれを NSAttributedString に変換したいのですが、最初の仕事は実際には重複とアンダースコアを排除することです。何かご意見は?

4

3 に答える 3

4

あなたの本当の目的は何ですか?man ページを表示したい場合、1 つのオプションは、それを HTML に変換し、Web ビューでレンダリングすることです。

Parsingmanの出力はgroff、デフォルトでターミナル プロセッサを使用して処理されるため、注意が必要です。これは、出力が端末デバイスに表示されるように調整されていることを意味します。

別の解決策の 1 つは、マニュアル ページのソース ファイルの実際の場所を特定することです。

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

(ASCII近似)および(カラー出力を無効にする)を使用groffして手動で呼び出します。-a-c

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

これにより、ほとんどのフォーマットが適用されていない ASCII ファイルが生成されます。HTML 出力を生成するには、

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

manparseman.conf などのカスタム構成ファイルでこれらのオプションを指定して、、、、およびを呼び出す代わりに、オプションをman使用してその構成ファイルを使用するように指示することもできます。デフォルトの構成ファイルは.-Cman -wgunzipgroff/private/etc/man.conf

また、適切なオプションを に渡すことで、おそらく端末デバイス プロセッサの出力を調整できますgrotty

于 2011-01-26T20:42:11.463 に答える
2

さて、これが私のソリューションの始まりですが、これを行うための追加の(より簡単な?)方法に興味があります。

ターミナルから返される出力は UTF-8 エンコーディングですが、NSUTF8StringEncoding は文字列を正しく解釈しません。その理由は、NSTask 出力のフォーマット方法にあります。

文字 N は、UTF-8 では 0x4e です。しかし、それに対応する NSData は 0x4e 0x08 0x4e です。0x08 はバックスペースに対応します。したがって、太字の場合、Terminal は letter-backspace-letter を出力します。

斜体の c の場合、UTF-8 では 0x63 です。NSData には 0x5f 0x08 0x63 が含まれ、0x5f はアンダースコアに対応します。したがって、斜体の場合、ターミナルはアンダースコア-バックスペース-文字を出力します。

この時点で、これらのシーケンスの生の NSData をスキャンする以外に、これを回避する方法は本当にありません。誰かが既存のコードを持っていない限り、完成したら、おそらくここにソースをパーサーに投稿します。一般的なプログラミング フレーズにあるように、コピーできるものを自分で作成しないでください。:)

ファローアップ:

man 出力を取得し、太字/下線付きの出力を NSMutableAttributedString の太字/下線付きの書式に置き換えるための、優れた高速パーサーをまとめました。他の誰かが同じ問題を解決する必要がある場合のコードは次のとおりです。

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)];
    }
}];
于 2011-01-26T18:10:06.697 に答える
1

もう 1 つの方法は、man ページを PostScript ソース コードに変換し、それを PostScript から PDF へのコンバーターを介して実行し、それを PDFView に配置することです。

実装は Bavarious の回答に似ていますが、 groff への引数が (-Tpsの代わりに-Thtml) 異なるだけです。

これは最も遅い解決策ですが、おそらく印刷には最適です。

于 2011-01-27T11:51:37.043 に答える