C、308または339バイト
#include <ctype.h>
#define p putchar
f(s,e,c,i,l)char*s,*e,*c;{i=1,l=40;if(*s++==l){p(l);for(c=s;i;i+=*c==l,i-=*c==41,i+*c==45&&p(44),c++);p(41);}for(;s<e;s=c){for(i=0;isdigit(*s);s+=*s==44)for(i&&p(32),i=1;isdigit(*s);s++)p(*s);*s==l&&p(l);for(c=s,i=1;++c,c<=e&&i;i+=*c==l)i-=*c==41;f(s,c-1);*s==l&&p(41);}}
#define g(x) f(x, x+strlen(x))
入力文字列の最後にポインタを渡すことが許可されているかどうかに応じて、308または339バイト。最後の行は、その長さを計算せずに文字列リテラルを直接渡すことができるようにするためだけのものです。
説明
非常に単純なアルゴリズム。現在の深さでコンマの数をカウントし、それらをタプルコンストラクタとして出力し、タプルの引数を追跡し、エスケープ(数値間のスペース、括弧間のネストされたタプル)、再帰的に。
#include <stdio.h>
#include <ctype.h>
typedef enum { false, true } bool;
void tup2ptsfree(char *s, char *e)
{
int depth;
char *c;
if (*s++ == '(') { /* If we are at the start of a tuple, write tuple function `(,,,)` (Otherwise, we are at a closing bracket or a comma) */
putchar('(');
/* do the search for comma's */
c=s; /* probe without moving the original pointer */
for (depth=1; depth != 0; c++) {
if (*c == '(') depth++;
if (*c == ')') depth--;
if (*c == ',' && depth == 1) putchar(','); /* We have found a comma at the right depth, print it */
}
putchar(')');
}
while (s < e) { /* The last character is always ')', we can ignore it and save a character. */
bool wroteNumber;
for (wroteNumber=false; isdigit(*s); wroteNumber = true) {
if (wroteNumber) p(' '); /* If this is not the first number we are writing, add a space */
while (isdigit(*s)) putchar(*s++); /* Prints the entire number */
if (*s == ',') s++; /* We found a ',' instead of a ')', so there might be more numbers following */
}
/* Add escaping parenthesis if we are expanding a tuple (Using a small if statement instead of a large branch to prevent doing the same thing twice, since the rest of the code is essentially the same for both cases). */
if (*s == '(') putchar('(');
/* Find a matching ')'... */
c=s+1;
for (depth=1; c <= e && depth != 0; c++) {
if (*c == '(') depth++;
if (*c == ')') depth--;
}
/* Found one */
/* Note how we are looking for a matching paren twice, with slightly different parameters. */
/* I couldn't find a way to golf this duplication away, though it might be possible. */
/* Expand the rest of the tuple */
tup2ptsfree(s, c-1);
/* idem */
if (*s == '(') putchar(')');
/* Make the end of the last expansion the new start pointer. */
s=c;
}
}
#define h(x) tup2ptsfree(x, x+strlen(x))
テストケースとアプリケーション
#include <stdio.h>
#define ARRAYSIZE(arr) (sizeof(arr)/sizeof(*arr))
static char *examples[] = {
"(1,2)",
"(10,1)",
"(1,2,3)",
"(1,2,3,4)",
"((1,2),3)",
"(1,(2,3))",
"(1,(2,3),4)",
"((1,2),(3,4))",
"((1,(2,3)),4,(5,6))",
"((1,((2,3), 4)),5,(6,7))",
"(42,48)",
"(1,2,3,4,5,6,7)"
};
int main(void)
{
int i;
for (i=0; i < ARRAYSIZE(examples); i++) {
printf("%-32s | \"", examples[i]);
g(examples[i]); /* Test with golfed version */
printf("\"\n");
printf("%-32s | \"", examples[i]);
h(examples[i]); /* Test with original version */
printf("\"\n");
}
}