00147-hard-c-printf-parser

Back

type ControlsMap = {
  c: "char";
  s: "string";
  d: "dec";
  o: "oct";
  h: "hex";
  f: "float";
  p: "pointer";
};

type ParsePrintFormat<S extends string> =
  S extends `${string}%${infer S}${infer Rest}`
    ? S extends keyof ControlsMap
      ? [ControlsMap[S], ...ParsePrintFormat<Rest>]
      : ParsePrintFormat<Rest>
    : [];

Solution by Vampirelee #32608

If I have understood correct the task is not adopted to TS language. So this is my solution for TS types (can be expanded for more symbols and types):

type ControlsMap = {
  s: string,
  d: number,
}

type Search<
  M extends string
> = M extends `${string}%${infer C extends keyof ControlsMap}${string}` ? ControlsMap[C] : never

type Loop<
  M extends string,
  P extends any[] = [],
> =
  M extends `${string}%${keyof ControlsMap}${infer E extends string}` ?
    E extends `${string}%${keyof ControlsMap}${string}` ? Loop<E, [...P, Search<M>]> :
    [...P, Search<M>]
  : never; 

declare function printf<M extends string>(
  message: M,
  ...args: Loop<M>,
): void;

// Some tests
printf("The result is %d.", 42); // Success
printf("The result is %d.", 'text'); // Error
printf("The result is %d %s.", 'text'); // Error
printf("The result is %s.", 'text'); // Success
printf("The result is %s %d.", 42); // Error
printf2("The result is %s %d.", 'text', 42); // Success

Solution by alexbidenko #32562

type ControlsMap = {
  c: 'char';
  s: 'string';
  d: 'dec';
  o: 'oct';
  h: 'hex';
  f: 'float';
  p: 'pointer';
};
type ParsePrintFormat<S extends string, R extends unknown[] = []> = S extends `${string}%${infer L}${infer LL}`
  ? L extends keyof ControlsMap
    ? ParsePrintFormat<`${LL}`, [...R, ControlsMap[L]]>
    : ParsePrintFormat<`${LL}`, [...R]>
  : R;

Solution by leejaehyup #31987

type ControlsMap = {
  c: 'char'
  s: 'string'
  d: 'dec'
  o: 'oct'
  h: 'hex'
  f: 'float'
  p: 'pointer'
}

type ParsePrintFormat<S extends string> = S extends `${string}%${infer L}${infer R}`
  ? L extends keyof ControlsMap
  ? [ControlsMap[L], ...ParsePrintFormat<R>]
  : ParsePrintFormat<R>
  : []

Solution by smileboyi #27494

// your answers
type ParsePrintFormat<S extends String, Res extends unknown[] = []> = 
  S extends `${infer X}%${infer Y}${infer Z}`
  ? Y extends keyof ControlsMap
    ? ParsePrintFormat<Z, [...Res, ControlsMap[Y]]>
    : ParsePrintFormat<Z, Res>
  : Res

Solution by kiki-zjq #26052

type ParsePrintFormat<T extends string> = T extends `${infer _}%${infer R1}`
  ? R1 extends `${infer F}${infer R2}`
    ? F extends keyof ControlsMap
      ? [ControlsMap[F], ...ParsePrintFormat<R2>]
      : ParsePrintFormat<R2>
    : []
  : [];

Solution by JohnLi1999 #25341

// your answers
type ParsePrintFormat<T extends string, Res extends string[] = [], Flag extends boolean = false> =
    T extends `${infer Left}${infer Rest}`
    ? Left extends '%'
    ? Flag extends false
    ? ParsePrintFormat<Rest, Res, true>
    : ParsePrintFormat<Rest, Res, false>
    : Flag extends true
    ? Left extends keyof ControlsMap
    ? ParsePrintFormat<Rest, [...Res, ControlsMap[Left]], false>
    : ParsePrintFormat<Rest, Res, false>
    : ParsePrintFormat<Rest, Res, false>
    : Res

Solution by studymachiney #25095

type SymbolCountType = 'odd' | 'even';

type ParsePrintFormat<T extends string, PrefixCount extends SymbolCountType = 'odd', R extends string[] = []> = T extends `${infer A} %${infer B}` ? HasMultiIdentifiers<T> extends true ? HandleMultiId<T, PrefixCount> : MatchPlaceholder<B, PrefixCount, [...R]> : [];

type HasMultiIdentifiers<M extends string> = M extends `${infer A} %${infer B} %${infer C}` ? true : false;

type HandleMultiId<H extends string, PrefixCount extends SymbolCountType = 'odd', R extends string[] = []> = H extends `${infer A} %${infer B} %${infer C}` ? HandleMultiId<C, PrefixCount, [...R, ...MatchPlaceholder<B, PrefixCount, []>]> : MatchPlaceholder<H, PrefixCount, [...R]>;

// type EndsWithDot<M extends string> = M extends `${infer C}.` ? true : false;
// type EndsWithColon<M extends string> = M extends `${infer C}:` ? true : false;

type GetValue<K extends string, Type extends SymbolCountType, R extends string[] = []> = Type extends 'odd' ? K extends keyof ControlsMap ? [...R, ControlsMap[K]] : [] : []; 

// 1. multiple %; 2. ends with width dot; 3. nil value; 4. multi placeholder indentifier
type MatchPlaceholder<U, L extends SymbolCountType = 'odd', R extends string[] = []> = U extends `%${infer A}` ? L extends 'odd' ? MatchPlaceholder<A, 'even', [...R]> : MatchPlaceholder<A, 'odd', [...R]> : U extends `${infer B}.` ? GetValue<B, L, R> : U extends `${infer S}:${infer N}` ? GetValue<S, L, R> : U extends string ? GetValue<U, L, R> : [];

Solution by yolilufei #24705

type ParsePrintFormat<T extends string> = T extends `${any}%${infer S}${infer R}` ?
  (S extends keyof ControlsMap ? [ControlsMap[S], ...ParsePrintFormat<R>] : ParsePrintFormat<R>) :
  [];

Solution by E-uler #24692

type ParsePrintFormat<T extends string, Acc extends unknown[] = []> = T extends `${string}%${infer Letter}${infer Rest}`
? Letter extends keyof ControlsMap
    ? ParsePrintFormat<Rest, [...Acc, ControlsMap[`${Letter}`]]>
    : ParsePrintFormat<Rest, Acc>
: Acc

Solution by NeylonR #24443

type ParsePrintFormat<PrintFS, Res extends string[] = []> = 
  PrintFS extends `%${infer F extends keyof ControlsMap}${infer R}` 
    ? ParsePrintFormat<R, [...Res, ControlsMap[F]]>
    : PrintFS extends `%%${infer R}` 
    ? ParsePrintFormat<R, Res>
    : PrintFS extends `${string}${infer R}` 
    ? ParsePrintFormat<R, Res> 
    : Res

Solution by flavianh #24363

// your answers
type Char = keyof ControlsMap


type ParsePrintFormat<S extends string,Result extends string[]= []> = S extends `${infer L}%${infer C}${infer R}`
? C extends Char 
  ? ParsePrintFormat<R,[...Result,ControlsMap[C]]>
  : ParsePrintFormat<R,Result>
:Result

Solution by walker-hzx #24302

type ParsePrintFormat<S extends string, R extends string[] = []> = S extends `${infer H}%${infer C}${infer T}` ? C extends keyof ControlsMap ? ParsePrintFormat<T, [...R, ControlsMap[C]]> : ParsePrintFormat<T, R> : R

Solution by sabercc #24216

type ParsePrintFormat<
  S extends string,
  U extends any[] = []
> = S extends `${infer Other}%${infer F}${infer R}`
  ? F extends keyof ControlsMap
    ? ParsePrintFormat<R, [...U, ControlsMap[F]]>
    : ParsePrintFormat<R, U>
  : U;

Solution by coderyoo1 #23018

// your answers
type ControlsMap = {
  c: 'char'
  s: 'string'
  d: 'dec'
  o: 'oct'
  h: 'hex'
  f: 'float'
  p: 'pointer'
}

type ParsePrintFormat<
  T,
  Acc extends unknown[] = []
> = T extends `${infer A}%${infer C}${infer D}`
  ? C extends keyof ControlsMap
    ? [...Acc, ControlsMap[C], ...ParsePrintFormat<D, Acc>] 
    : [...Acc, ...ParsePrintFormat<D, Acc>] 
  : Acc

Solution by jxhhdx #22823

interface ControlsMap {
  c: 'char'
  s: 'string'
  d: 'dec'
  o: 'oct'
  h: 'hex'
  f: 'float'
  p: 'pointer'
}

type ParsePrintFormat<S extends string, V extends unknown[] = []> =
  S extends `${infer L}%${infer P}${infer R}`
    ? P extends keyof ControlsMap
      ? ParsePrintFormat<`${L}${R}`, [...V, ControlsMap[P]]>
      : ParsePrintFormat<`${L}${R}`, V>
    : V

Solution by drylint #22212

// your answers
type ParsePrintFormat<T extends string, R extends string[] = [], G extends boolean = false> = 
T extends `${infer First}${infer Rest}` 
? G extends true
  ? First extends keyof ControlsMap 
    ? ParsePrintFormat<Rest, [...R, ControlsMap[First]], false> 
    : First extends '%' ? ParsePrintFormat<Rest, R, false> : ParsePrintFormat<Rest, R, false>
  : First extends '%' ? ParsePrintFormat<Rest, R, true> : ParsePrintFormat<Rest, R, false>
: R

Solution by 437204933 #22049

type ParsePrintFormat<S extends string> = S extends `${string}%${infer C}${infer Rest}` ? 
[...(C extends keyof ControlsMap ? [ControlsMap[C]] : []), ...ParsePrintFormat<Rest>] : [];

Solution by Karamuto #21950

type ParsePrintFormat<S extends string> = 
  S extends `${any}%${infer K}${infer R}`
    ? [...(K extends keyof ControlsMap ? [ControlsMap[K]] : []), ...ParsePrintFormat<R>]
    : [];

Solution by ivbrajkovic #21637

ype ParsePrintFormat<T,Result extends Array<string> = []> = 
  T extends `${infer A}%${infer B}${infer C}` ? 
     B extends keyof ControlsMap ? 
         ParsePrintFormat<C,[...Result,ControlsMap[B]]> : 
         ParsePrintFormat<C,Result> : 
  Result```

Solution by so11y #21097

type ParsePrintFormat<S extends string> = S extends `${string}%${infer TControl extends keyof ControlsMap}${infer TRight}`
  ? [ControlsMap[TControl], ...ParsePrintFormat<TRight>]
  : S extends `${string}%${string}${infer TRight}` ? ParsePrintFormat<TRight>
  : [];

Solution by mdakram28 #20644

// your answers
type RemoveSymbol<S extends string> = S extends `%${infer R}` ? R : S

type ParsePrintFormat<S> = S extends `${infer F} %${infer P extends keyof ControlsMap}${infer Sybmol}${infer Rest}`
 ? [...[ControlsMap[P],...ParsePrintFormat<Rest>]] : 
S extends `${infer G} %${infer H}.`
 ? ParsePrintFormat<`${G} ${RemoveSymbol<H>}.`> : []

Solution by YqxLzx #20518

type ParsePrintFormat<T extends string> = T extends `${string}%${infer K}${infer O}`
  ? K extends keyof ControlsMap
    ? [ControlsMap[K], ...ParsePrintFormat<O>]
    : ParsePrintFormat<O>
  : []

Solution by pengzhanbo #20510

// your answers
// 1. 找出以 % 开头的特殊字符,调用 HandlerChar 进行处理;
//  - 需要考虑 %开头的字符是否是适用的,既偶数%是不需要做处理(不需要从 controlMap中取结果),奇数%是需要进行处理的。用 Last 字段来进行判断,当前Char 与 LastChar 都是 % 需要对对碰,清空,将Last变为 ‘’继续递归处理 str 直到 当前字符为 ControlMap 的 key并且Last 为 % 表明是我们想要的结果
// 将结果和 剩余字符串以数组的形式返回,方便后续处理;
// 2. 根据 HandlerChar 返回的结果,只有在是数组的情况才是我们需要保存的,字符串的话需要继续递归调用 FindSpChar
type ControlsMap = {
  c: 'char'
  s: 'string'
  d: 'dec'
  o: 'oct'
  h: 'hex'
  f: 'float'
  p: 'pointer'
}
type HandleChar<C extends string,Last extends string = '', Ret extends string[] = []> = C extends `${infer First}${infer Rest}` ?First extends '%' ? Last extends '%' ? HandleChar<Rest,'',Ret>: HandleChar<Rest, '%', Ret> : First extends keyof ControlsMap ? Last extends '%' ? [ControlsMap[First],Rest] : Rest : Rest : ''
type FindSpChar<S extends string, Ret extends string[] = []>= S extends `${infer Header}%${infer Rest}` ? HandleChar<`%${Rest}`> extends infer HRes ? HRes extends any[] ? FindSpChar<HRes[1],[...Ret,HRes[0]]>:HRes extends string ? FindSpChar<HRes,Ret>: never : never: Ret
type res = FindSpChar<`%%%d..`>
type ParsePrintFormat<S extends string> = FindSpChar<S>

Solution by Rebornjiang #20481

type ControlsMap = {
  c: 'char'
  s: 'string'
  d: 'dec'
  o: 'oct'
  h: 'hex'
  f: 'float'
  p: 'pointer'
}

type AllowedLetters = keyof ControlsMap
type AllowedValues = ControlsMap[AllowedLetters]

type ParsePrintFormat<S extends string, Acc extends AllowedValues[] = []> = 
  S extends `${any}%${infer Letter}${infer Rest}`
    ? Letter extends AllowedLetters
      ? ParsePrintFormat<Rest, [...Acc, ControlsMap[Letter]]>
      : ParsePrintFormat<Rest, Acc>
    : Acc

Solution by zhaoyao91 #20443

type ControlsMap = {
  c: 'char'
  s: 'string'
  d: 'dec'
  o: 'oct'
  h: 'hex'
  f: 'float'
  p: 'pointer'
}

type ParsePrintFormat<S extends string> = S extends `${string}%${infer A}`
  ? A extends `${infer F}${infer B}`
    ? F extends keyof ControlsMap
      ? [ControlsMap[F], ...ParsePrintFormat<B>]
      : ParsePrintFormat<B>
    : []
  : []

Solution by theoolee #19575

type ControlsMap = {
  c: 'char';
  s: 'string';
  d: 'dec';
  o: 'oct';
  h: 'hex';
  f: 'float';
  p: 'pointer';
};

type ParsePrintFormat<S extends string, Result extends string[] = []> = S extends `${infer F}${infer M}${infer R}`
  ? F extends '%'
    ? M extends keyof ControlsMap
      ? ParsePrintFormat<R, [...Result, ControlsMap[M]]>
      : ParsePrintFormat<R, Result>
    : ParsePrintFormat<`${M}${R}`, Result>
  : Result;

Solution by CaoXueLiang #19026

type ControlsMap = {
  c: 'char'
  s: 'string'
  d: 'dec'
  o: 'oct'
  h: 'hex'
  f: 'float'
  p: 'pointer'
}

type ParsePrintFormat<T> = T extends `${infer L}${infer M}${infer R}`
  ? L extends '%'
    ? M extends keyof ControlsMap
      ? [ControlsMap[M], ...ParsePrintFormat<`${R}`>]
      : ParsePrintFormat<`${R}`>
    : ParsePrintFormat<`${M}${R}`>
  : []

Solution by milletlovemouse #18497

type ControlsMap = {
  c: 'char'
  s: 'string'
  d: 'dec'
  o: 'oct'
  h: 'hex'
  f: 'float'
  p: 'pointer'
};

type ParsePrintFormat<
  S extends string,
  Result extends string[] = [],
  Cnt extends 0[] = []
> = S extends `${infer F}${infer R}` ?
  F extends '%' ?
    ParsePrintFormat<R, Result, Cnt['length'] extends 2 ? [0] : [...Cnt, 0]> :
    Cnt['length'] extends 1 ?
      ParsePrintFormat<R, F extends keyof ControlsMap ? [...Result, ControlsMap[F]] : Result, []> :
      ParsePrintFormat<R, Result, []> :
  Result;

Solution by CallMeSaltyF1sh #18284

// your answers
type ParsePrintFormat<T extends string, R extends string[] = []> = T extends `${infer f}${infer s}${infer r}` 
 ? f extends '%'
    ? s extends keyof ControlsMap
      ? ParsePrintFormat<r, [...R, ControlsMap[s]]>
      : ParsePrintFormat<r, R>
    : ParsePrintFormat<`${s}${r}`, R>
 : R

Solution by seho-dev #17578