Skip to main content
Code Review

Return to Question

added 694 characters in body
Source Link
Chris_F
  • 347
  • 2
  • 9

Now just for fun, I converted this to JavaScript with regex...

function format(fmt, ...args) {
 if (!fmt.match(/^(?:(?:(?:[^{}]|(?:\{\{)|(?:\}\}))+)|(?:\{[0-9]+\}))+$/)) {
 throw new Error('invalid format string.');
 }
 return fmt.replace(/((?:[^{}]|(?:\{\{)|(?:\}\}))+)|(?:\{([0-9]+)\})/g, (m, str, index) => {
 if (str) {
 return str.replace(/(?:{{)|(?:}})/g, m => m[0]);
 } else {
 if (index >= args.length) {
 throw new Error('argument index is out of range in format');
 }
 return args[index];
 }
 });
}
function print(fmt, ...args) {
 console.log(format(fmt, ...args));
}
print("Hello, {0}! The answer is {1}.", "World", 42);

Now just for fun, I converted this to JavaScript with regex...

function format(fmt, ...args) {
 if (!fmt.match(/^(?:(?:(?:[^{}]|(?:\{\{)|(?:\}\}))+)|(?:\{[0-9]+\}))+$/)) {
 throw new Error('invalid format string.');
 }
 return fmt.replace(/((?:[^{}]|(?:\{\{)|(?:\}\}))+)|(?:\{([0-9]+)\})/g, (m, str, index) => {
 if (str) {
 return str.replace(/(?:{{)|(?:}})/g, m => m[0]);
 } else {
 if (index >= args.length) {
 throw new Error('argument index is out of range in format');
 }
 return args[index];
 }
 });
}
function print(fmt, ...args) {
 console.log(format(fmt, ...args));
}
print("Hello, {0}! The answer is {1}.", "World", 42);
replaced http://codereview.stackexchange.com/ with https://codereview.stackexchange.com/
Source Link

This is my second attempt (version 1 version 1) at writing a string formatting utility which uses parsing. This time I more explicitly designed it as a finite state machine. I have very little experience with writing FSMs. As before, I'm not 100% sure that this code does not contain any critical flaws. In addition to pointing out any such oversights, I would appreciate advice on how this could be modified to make it either faster or more readable.

This is my second attempt (version 1) at writing a string formatting utility which uses parsing. This time I more explicitly designed it as a finite state machine. I have very little experience with writing FSMs. As before, I'm not 100% sure that this code does not contain any critical flaws. In addition to pointing out any such oversights, I would appreciate advice on how this could be modified to make it either faster or more readable.

This is my second attempt (version 1) at writing a string formatting utility which uses parsing. This time I more explicitly designed it as a finite state machine. I have very little experience with writing FSMs. As before, I'm not 100% sure that this code does not contain any critical flaws. In addition to pointing out any such oversights, I would appreciate advice on how this could be modified to make it either faster or more readable.

Tweeted twitter.com/#!/StackCodeReview/status/488696793656733696
edited body
Source Link
Chris_F
  • 347
  • 2
  • 9
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
#include <exception><stdexcept>
#include <utility>
#include <cctype>
using std::to_string;
template <class T>
std::string to_string(T&& item)
{
 return boost::lexical_cast<std::string>(std::forward<T>(item)); 
}
template <class... Args>
std::string format(const std::string& fmt, Args&&... args)
{
 std::string arg_strs[] = { to_string(std::forward<Args>(args))... };
 
 std::string output, index;
 output.reserve(fmt.length() * 2);
 
 enum { COPYING, OPEN_BRACE, READ_INDEX, CLOSE_BRACE } state = COPYING;
 for (const char c : fmt) 
 {
 switch (state)
 {
 case COPYING:
 if (c == '{') state = OPEN_BRACE;
 else if (c == '}') state = CLOSE_BRACE;
 else output += c;
 break;
 
 case OPEN_BRACE:
 if (isdigit(c)) {
 index += c;
 state = READ_INDEX;
 }
 else if (c == '{') {
 output += '{';
 state = COPYING;
 }
 else goto fail;
 break;
 
 case READ_INDEX:
 if (isdigit(c)) index += c;
 else if (c == '}') {
 size_t i = std::stoi(index);
 if (i >= sizeof...(args)) {
 throw std::out_of_range(
 "argument index is out of range in format");
 }
 output += arg_strs[i];
 index.clear();
 state = COPYING;
 }
 else goto fail;
 break;
 
 case CLOSE_BRACE:
 if (c == '}') {
 output += '}';
 state = COPYING;
 }
 else goto fail;
 break;
 }
 }
 if (state != COPYING) goto fail;
 return output;
 
fail:
 throw std::invalid_argument("invalid format string");
}
template <class... Args>
void print(const std::string& fmt, Args&&... args)
{
 std::cout << format(fmt, std::forward<Args>(args)...);
}
int main()
{
 print("Hello, {0}! The answer is {1}.", "World", 42);
}
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
#include <exception>
#include <utility>
#include <cctype>
using std::to_string;
template <class T>
std::string to_string(T&& item)
{
 return boost::lexical_cast<std::string>(std::forward<T>(item)); 
}
template <class... Args>
std::string format(const std::string& fmt, Args&&... args)
{
 std::string arg_strs[] = { to_string(std::forward<Args>(args))... };
 
 std::string output, index;
 output.reserve(fmt.length() * 2);
 
 enum { COPYING, OPEN_BRACE, READ_INDEX, CLOSE_BRACE } state = COPYING;
 for (const char c : fmt) 
 {
 switch (state)
 {
 case COPYING:
 if (c == '{') state = OPEN_BRACE;
 else if (c == '}') state = CLOSE_BRACE;
 else output += c;
 break;
 
 case OPEN_BRACE:
 if (isdigit(c)) {
 index += c;
 state = READ_INDEX;
 }
 else if (c == '{') {
 output += '{';
 state = COPYING;
 }
 else goto fail;
 break;
 
 case READ_INDEX:
 if (isdigit(c)) index += c;
 else if (c == '}') {
 size_t i = std::stoi(index);
 if (i >= sizeof...(args)) {
 throw std::out_of_range(
 "argument index is out of range in format");
 }
 output += arg_strs[i];
 index.clear();
 state = COPYING;
 }
 else goto fail;
 break;
 
 case CLOSE_BRACE:
 if (c == '}') {
 output += '}';
 state = COPYING;
 }
 else goto fail;
 break;
 }
 }
 if (state != COPYING) goto fail;
 return output;
 
fail:
 throw std::invalid_argument("invalid format string");
}
template <class... Args>
void print(const std::string& fmt, Args&&... args)
{
 std::cout << format(fmt, std::forward<Args>(args)...);
}
int main()
{
 print("Hello, {0}! The answer is {1}.", "World", 42);
}
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
#include <stdexcept>
#include <utility>
#include <cctype>
using std::to_string;
template <class T>
std::string to_string(T&& item)
{
 return boost::lexical_cast<std::string>(std::forward<T>(item)); 
}
template <class... Args>
std::string format(const std::string& fmt, Args&&... args)
{
 std::string arg_strs[] = { to_string(std::forward<Args>(args))... };
 
 std::string output, index;
 output.reserve(fmt.length() * 2);
 
 enum { COPYING, OPEN_BRACE, READ_INDEX, CLOSE_BRACE } state = COPYING;
 for (const char c : fmt) 
 {
 switch (state)
 {
 case COPYING:
 if (c == '{') state = OPEN_BRACE;
 else if (c == '}') state = CLOSE_BRACE;
 else output += c;
 break;
 
 case OPEN_BRACE:
 if (isdigit(c)) {
 index += c;
 state = READ_INDEX;
 }
 else if (c == '{') {
 output += '{';
 state = COPYING;
 }
 else goto fail;
 break;
 
 case READ_INDEX:
 if (isdigit(c)) index += c;
 else if (c == '}') {
 size_t i = std::stoi(index);
 if (i >= sizeof...(args)) {
 throw std::out_of_range(
 "argument index is out of range in format");
 }
 output += arg_strs[i];
 index.clear();
 state = COPYING;
 }
 else goto fail;
 break;
 
 case CLOSE_BRACE:
 if (c == '}') {
 output += '}';
 state = COPYING;
 }
 else goto fail;
 break;
 }
 }
 if (state != COPYING) goto fail;
 return output;
 
fail:
 throw std::invalid_argument("invalid format string");
}
template <class... Args>
void print(const std::string& fmt, Args&&... args)
{
 std::cout << format(fmt, std::forward<Args>(args)...);
}
int main()
{
 print("Hello, {0}! The answer is {1}.", "World", 42);
}
added 116 characters in body
Source Link
Chris_F
  • 347
  • 2
  • 9
Loading
Source Link
Chris_F
  • 347
  • 2
  • 9
Loading
lang-cpp

AltStyle によって変換されたページ (->オリジナル) /