문제

I need a method to parse ANSI color codes from a shell output in order to set the respective color attributes for a NSAttributedString.

The input string looks something like:

[0;31mThis should be RED colored.[0;34m This should be BLUE colored. [0;32mThis should be GREEN colored.[0;31mThis should be RED too.

Somehow my code is mismatching the colors after i am removing the Ansi Codes from the output. My current code follows:

- (NSAttributedString*)ansicodeParser:(NSString *)str
{
    // init string
    NSMutableString           *mutableStr    = [[NSMutableString alloc] initWithString:str];
    NSMutableAttributedString *attributedStr = [[NSMutableAttributedString alloc]initWithString:str];

    // set default text attributes
    [attributedStr addAttribute:NSForegroundColorAttributeName value:[UIColor whiteColor] range:NSMakeRange(0,[attributedStr length])];
    [attributedStr addAttribute:NSBackgroundColorAttributeName value:[UIColor blackColor] range:NSMakeRange(0,[attributedStr length])];


    // init ansiColors dict
    NSDictionary *ansiColors = @{
        // Resets
        @"\\[H"     : @{ NSForegroundColorAttributeName : [UIColor whiteColor] },    // Text Reset
        @"\\[J"     : @{ NSForegroundColorAttributeName : [UIColor whiteColor] },    // Text Reset
        @"\\[0m"    : @{ NSForegroundColorAttributeName : [UIColor whiteColor] },    // Text Reset

        // Regular Text + Colors
        @"\\[0;30m" : @{ NSForegroundColorAttributeName : [UIColor blackColor] },    // Black
        @"\\[0;31m" : @{ NSForegroundColorAttributeName : [UIColor redColor] },      // Red
        @"\\[0;32m" : @{ NSForegroundColorAttributeName : [UIColor greenColor] },    // Green
        @"\\[0;33m" : @{ NSForegroundColorAttributeName : [UIColor yellowColor] },   // Yellow
        @"\\[0;34m" : @{ NSForegroundColorAttributeName : [UIColor blueColor] },     // Blue
        @"\\[0;35m" : @{ NSForegroundColorAttributeName : [UIColor purpleColor] },   // Purple
        @"\\[0;36m" : @{ NSForegroundColorAttributeName : [UIColor cyanColor] },     // Cyan
        @"\\[0;37m" : @{ NSForegroundColorAttributeName : [UIColor whiteColor] },    // White

        // Bold Text + Colors
        @"\\[1;30m" : @{ NSForegroundColorAttributeName : [UIColor blackColor] },    // Black
        @"\\[1;31m" : @{ NSForegroundColorAttributeName : [UIColor redColor] },      // Red
        @"\\[1;32m" : @{ NSForegroundColorAttributeName : [UIColor greenColor] },    // Green
        @"\\[1;33m" : @{ NSForegroundColorAttributeName : [UIColor yellowColor] },   // Yellow
        @"\\[1;34m" : @{ NSForegroundColorAttributeName : [UIColor blueColor] },     // Blue
        @"\\[1;35m" : @{ NSForegroundColorAttributeName : [UIColor purpleColor] },   // Purple
        @"\\[1;36m" : @{ NSForegroundColorAttributeName : [UIColor cyanColor] },     // Cyan
        @"\\[1;37m" : @{ NSForegroundColorAttributeName : [UIColor whiteColor] },    // White

        // Underlined Text + Colors
        @"\\[4;30m" : @{ NSForegroundColorAttributeName : [UIColor blackColor] },    // Black
        @"\\[4;31m" : @{ NSForegroundColorAttributeName : [UIColor redColor] },      // Red
        @"\\[4;32m" : @{ NSForegroundColorAttributeName : [UIColor greenColor] },    // Green
        @"\\[4;33m" : @{ NSForegroundColorAttributeName : [UIColor yellowColor] },   // Yellow
        @"\\[4;34m" : @{ NSForegroundColorAttributeName : [UIColor blueColor] },     // Blue
        @"\\[4;35m" : @{ NSForegroundColorAttributeName : [UIColor purpleColor] },   // Purple
        @"\\[4;36m" : @{ NSForegroundColorAttributeName : [UIColor cyanColor] },     // Cyan
        @"\\[4;37m" : @{ NSForegroundColorAttributeName : [UIColor whiteColor] },    // White

        // Background Colors
        @"\\[40m"   : @{ NSBackgroundColorAttributeName : [UIColor blackColor] },    // Black
        @"\\[41m"   : @{ NSBackgroundColorAttributeName : [UIColor redColor] },      // Red
        @"\\[42m"   : @{ NSBackgroundColorAttributeName : [UIColor greenColor] },    // Green
        @"\\[43m"   : @{ NSBackgroundColorAttributeName : [UIColor yellowColor] },   // Yellow
        @"\\[44m"   : @{ NSBackgroundColorAttributeName : [UIColor blueColor] },     // Blue
        @"\\[45m"   : @{ NSBackgroundColorAttributeName : [UIColor purpleColor] },   // Purple
        @"\\[46m"   : @{ NSBackgroundColorAttributeName : [UIColor cyanColor] },     // Cyan
        @"\\[47m"   : @{ NSBackgroundColorAttributeName : [UIColor whiteColor] },    // White
    };

    // set color attribute
    for(NSString *ansiStr in ansiColors)
    {
        // search ansicode in output
        NSRegularExpression *regex    = [NSRegularExpression regularExpressionWithPattern:ansiStr options:NSRegularExpressionCaseInsensitive error:nil];
        NSMutableArray      *matches  = (NSMutableArray*)[regex matchesInString:mutableStr options:0 range:NSMakeRange(0, mutableStr.length)];

        for (NSTextCheckingResult *match in matches)
        {
            // gather values
            NSRange wordRange   = [match rangeAtIndex:0];
            UIColor  *fontColor = [[ansiColors objectForKey:ansiStr] objectForKey:NSForegroundColorAttributeName];
            UIColor  *backColor = [[ansiColors objectForKey:ansiStr] objectForKey:NSBackgroundColorAttributeName];

            // set foreground color
            if(fontColor != nil)
                [attributedStr addAttribute:NSForegroundColorAttributeName value:fontColor range:NSMakeRange(wordRange.location+wordRange.length, [[[attributedStr mutableString] substringFromIndex:wordRange.location] length] - wordRange.length)];

            // set background color
            if(backColor != nil)
                [attributedStr addAttribute:NSBackgroundColorAttributeName value:backColor range:NSMakeRange(wordRange.location+wordRange.length, [[[attributedStr mutableString] substringFromIndex:wordRange.location] length] - wordRange.length)];
        }
    }

    // remove ansicodes from output
    for(NSString *ansiStr in ansiColors)
    {
        [[attributedStr mutableString] replaceOccurrencesOfString:[ansiStr substringFromIndex:1] withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, attributedStr.length)];
    }

    // return formatted console output
    return (NSAttributedString*)attributedStr;
}
도움이 되었습니까?

해결책

You need to approach it differently. You cannot set attribute ranges and then modify the string in this way. That changes the range of the attribute. There are lots of ways to do it. An easier way to do this without getting confused is to first split the string into an array based on the matches. Then remove the ANSI color prefix from each string in the array and apply the color. Then join the array into one string.

Another approach would be to first convert the non-attributed string to another format. It could be HTML or RTF for example. Then all you would be doing is converting the ANSI color tags to a format that the cocoa text system can already handle for you.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top