シェルのC文字列リテラルの解析

シェルのC文字列リテラルの解析

実際の表現に変換したい有効なC文字列リテラルがあります。残念ながら、printfの%b変換指定子はC文字列で有効ですか?エスケープ文字 ' と ' を定義しません。

今は変換を実行する小さなCプログラムがありますが、標準のPOSIXツールを使用してすべてのことを実行できることを願っています。

POSIXツール(GNUismsなし)でのみ機能し、必要に応じてbashを実行することもできますが、shが優先されます。

ベストアンサー1

私はawkでこれを行う方法を考えました。しかし、少し見苦しく、誰もがより良い解決策を持っているなら、興味があるでしょう。これはすべての有効なC文字列に対して機能しますが、無効な文字列のすべてのケースを処理するわけではありません(例:\ q、ここでqはバックスラッシュの後に続く無効な文字であり、その文字のみを使用します)。

function hexnumber(str,  ret, n, k)
{
    n = length(str)
    ret = 0
    for (i = 1; i <= n; i++) {
        c = substr(str, i, 1)
        c = tolower(c)
        # index() returns 0 if c not in string,
        # includes c == "0"
        k = index("123456789abcdef", c)

        ret = ret * 16 + k
    }
    return ret;
}

function octnumber(str,  ret, n, k)
{
    n = length(str)
    ret = 0
    for (i = 1; i <= n; i++) {
        c = substr(str, i, 1)
        # index() returns 0 if c not in string,
        # includes c == "0"
        k = index("1234567", c)

        ret = ret * 8 + k
    }
    return ret;
}


BEGIN { RS="\\" ; notQuoted = 0}
#{ print $0 ; next}
NR == 1 {
    if(match($0,/^"/)) {
        split($0,matches,"\"")
        printf("%s",matches[2]);
        if(match($0,/^"[^"]*"/)) {
            exit 0;
        }
        next
    } else {
        exit 1;
    }
}

#This will happen on the 2nd (and subsequent) consecutive backslash
/^$/ {
    if (notQuoted) {
        notQuoted = 0
    } else {
    notQuoted = 1
    printf("\\")
    next
    }
}
notQuoted == 1 {
    if(match($0,/([^"]*)"/))
    {
        split($0,matches,"\"")
        printf("%s",matches[1])
        exit 0
    }
    printf("%s",$0);
    next
}
# If we reach here, then the first character is part of a backslash escape
{
    first = substr($0,1,1);
    rest = substr($0,2);

    if(first == "a") printf("\a")
    else if(first == "b") printf("\b")
        else if(first == "f") printf("\f")
        else if(first == "n") printf("\n")
        else if(first == "r") printf("\r")
        else if(first == "t") printf("\t")
        else if(first == "v") printf("\v")
        else if(first == "\"") printf("\"")
        else if (first == "x") {
            second = substr(rest,1,1);
            third = substr(rest,2,1);
            if(match(third,/[1234567890ABCDEFabcdef]/)) {
                printf("%c",hexnumber(second third)+0);
                rest = substr(rest,3);
            }
            else {
                printf("%c",hexnumber(second)+0);
                rest = substr(rest,2);
            }
        }
        else if (match(first,/[01234567]/)) {
            second = substr(rest,1,1);
            third = substr(rest,2,1);
            fourth = substr(rest,3,1);
            if(match(second third fourth,/^[01234567]*$/)) {
                printf("%c",octnumber("0" first second third fourth)+0);
                rest = substr(rest,length(first second third fourth));
            }
            else if(match(second third,/^[01234567]*$/)) {
                printf("%c",octnumber(first second third)+0);
                rest = substr(rest,length(first second third));
            }
            else if(match(second,/^[01234567]*$/)) {
                printf("%c",octnumber(first second)+0);
                rest = substr(rest,length(first second));
            }
            else {
                printf("%c",octnumber(first)+0);
            }
        }

    if(match(rest,/([^"]*)"/))  # this comment fixes vim's syntax matching " 
    {
        split(rest,matches,"\"")
        printf("%s",matches[1])
        exit 0
    }

    printf("%s",rest);
}

おすすめ記事