How to check that vsprintf has the correct number of arguments before running
I'm trying to use vsprintf() to output a formatted string, but I need to validate that I have the correct number of arguments before running it to prevent "Too few arguments" errors.
In essence I think what I need is a regex to count the numbe开发者_Python百科r of type specifiers, but I'm pretty useless when it comes to regex and I couldn't fund it anywhere so I thought I'd give SO a go. :)
Unless you can think of a better way this method is along the lines of what I want.
function __insertVars($string, $vars = array()) {
$regex = '';
$total_req = count(preg_match($regex, $string));
if($total_req === count($vars)) {
return vsprintf($string, $vars);
}
}
Please tell me if you can think of a simpler way.
I think your solution is the only way to more or less reliably tell how many arguments are in the string.
Here is the regular expression I came up with, use it with preg_match_all()
:
%[-+]?(?:[ 0]|['].)?[a]?\d*(?:[.]\d*)?[%bcdeEufFgGosxX]
Based upon sprintf()
documentation. Should be compatible with PHP 4.0.6+ / 5.
EDIT - A slightly more compact version:
%[-+]?(?:[ 0]|'.)?a?\d*(?:\.\d*)?[%bcdeEufFgGosxX]
Also, take advantage of the func_get_args()
and func_num_args()
functions in your code.
EDIT: - Updated to support positional/swapping arguments (not tested):
function validatePrintf($format, $arguments)
{
if (preg_match_all("~%(?:(\d+)[$])?[-+]?(?:[ 0]|['].)?(?:[-]?\d+)?(?:[.]\d+)?[%bcdeEufFgGosxX]~", $format, $expected) > 0)
{
$expected = intval(max($expected[1], count(array_unique($expected[1]))));
if (count((array) $arguments) >= $expected)
{
return true;
}
}
return false;
}
var_dump(validatePrintf('The %2$s contains %1$d monkeys', array(5, 'tree')));
I think it's very easy, because it returns FALSE value if something wrong. You can check like this:
if (vsprintf($string, $wrongArray) === false) {
// vsprintf has wrong number of arguments
}
I used Alix Axel answer and created universal function.
We have a $countArgs
(from function parameters) and $countVariables
(from $format
like %s
).
For example:
$object->format('Hello, %s!', ['Foo']); // $countArgs = 1, $countVariables = 1;
Print: Hello, Foo!
$object->format('Hello, %s! How are you, %s?', ['Bar']); // $countArgs = 1, $countVariables = 2;
Print: Error.
Function:
public static function format($format, array $args)
{
$pattern = "~%(?:(\d+)[$])?[-+]?(?:[ 0]|['].)?(?:[-]?\d+)?(?:[.]\d+)?[%bcdeEufFgGosxX]~";
$countArgs = count($args);
preg_match_all($pattern, $format, $expected);
$countVariables = isset($expected[0]) ? count($expected[0]) : 0;
if ($countArgs !== $countVariables) {
throw new \Exception('The number of arguments in the string does not match the number of arguments in a template.');
} else {
return $countArgs > 1 ? vsprintf($format, $args) : sprintf($format, reset($args));
}
}
精彩评论