The regular solution (Marius Gavrilescu)
Since format specifiers are whole words, we can iterate through the words of the format string, passing each of them to printf (with an argument if needed). We will use a
std::map
to map variable names to values.
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<map>
5
6 std::map<char, char*> vars; // Map from variable names to values
7 char c, s[105], *vs; // vs points to the name of the previous variable
8
9 char* next() { // This function returns the name of the next variable
10 vs+=2; // Advance to the next variable name
11 return vars[*vs]; // Return the value of the variable
12 }
13
14 int main(){
15 int n;
16 scanf("%d ", &n); // Read the number of variables
17 while(n--){
18 scanf("%c=%s ", &c, s); // Read the variable name and value
19 vars[c] = strdup(s); // Store the variable in the map
20 }
21 fgets(s, 105, stdin); // Read the last line
22
23 vs = strchr(s, ',') - 1; // Two characters before the first variable name
24 vs[1] = 0; // Remove the comma to terminate the format string here
25
26 for(char *w = strtok(s, " "); w != NULL; w = strtok(NULL, " ")){
27 char type = w[strlen(w) - 1]; // The last character of this word, e.g. d for %5d
28 if(w[0] != '%') // If the word is not a format specifier...
29 printf(w); // ...print it directly
30 else if(type == 's') // If the format specifier ends with a s...
31 printf(w, next()); // ...pass it to printf as-is (= as a string)
32 else if(type == 'd') // If the format specifier ends with a d...
33 printf(w, atoi(next())); // ...pass it to printf as an int
34 else // Otherwise (if it ends with a f)...
35 printf(w, atof(next())); // ...pass it to printf as a float
36 putchar(' '); // Put a space after this word
37 }
38
39 return 0;
40 }
The easy solution (Marius Gavrilescu)
An easier way to solve this problem is to directly call printf with the given format string and arguments. This
can't be done portably in C. Fortunately, some other languages do not have this restriction.
1 #!/usr/bin/perl
2 use v5.14;
3 use warnings;
4
5 my @args = <>; # Read all lines
6 chomp @args; # Remove the final newline from all lines
7 shift @args; # Get rid of the first line
8 my ($format, @vars) = split ',', pop @args; # Split the last line into a format string and variables
9 my %args = map { split '=' } @args; # Create a hash from variable names to values
10
11 printf $format, map { $args{$_} } @vars; # Pass the format string and variable values to printf