4

I have problem with one problem on HackersRank - Day 16: Exceptions - String to Integer . In short task is

Read a string, SS, and print its integer value; if SS cannot be converted to an integer, print Bad StringBad String.

Note: You must use the String-to-Integer and exception handling constructs built into your submission language. If you attempt to use loops/conditional statements, you will get a 00 score.

Task itself is quite simple and I solved it on Python. My problem is fact that I don't see the way to do that with PHP - is there function in PHP that throws Exception if you are trying to convert string to integer?

2
  • 1
    Nothing built-in, AFAIK. Casting strings to integers only results in the int value 0, if the string can’t be parsed as a numeric value – it doesn’t throw an exception. You might have to implement that yourself, by checking if the string content is a valid number, and then throwing an exception yourself if not. Commented Apr 7, 2016 at 18:06
  • Hahaha. What HackerRank wants the developer to accomplish: Using try-catch blocks. What PHP developer ends up accomplishing: fixing internal PHP functions. I am sure HackerRank didn't mean that. Commented Mar 7, 2019 at 16:31

10 Answers 10

12

And here's another hacky solution using the try {..} catch mechanism:

try {
    new ReflectionClass('ReflectionClass' . ((int)$SS . "" !== $SS));
    echo $SS;
} catch (Exception $e) {
    echo "Bad StringBad String";
}

It works like this: if the string $SS doesn't actually resolve to an integer, the code will try to lookup the ReflectionClass1 class, which, in the end, will throw a ReflectionException.

The parsing works by simply casting $SS to int and then back to string and comparing it to the initial value.

Sign up to request clarification or add additional context in comments.

1 Comment

same question on hackerrank.com/challenges/…. but your answer no pass test case You should use exception handling concepts.
9

Only for php 7 (HackersRank uses it):

class Printer {
    public static function printInt(int $value) {
        echo $value;
    }
}

$handle = fopen ("php://stdin","r");
fscanf($handle,"%s",$S);
try {
    sscanf($S, "%d", $out);
    Printer::printInt($out);
} catch (TypeError $e) {
    echo "Bad String";
}

2 Comments

Forcing PHP to use the built-in type check. That is neat.
Worked out for me. Think this is the best solution
7

In general, no. PHP is weakly typed, so you can change integers to strings and vice-versa without any special work. (emphasis mine)

PHP is a dynamic, loosely typed language, that uses copy-on-write and reference counting.
To clarify what exactly is meant by the statement above: PHP is a high level language, weak typing is implicit of the engines preference to convert, or coerce variables into the required type at execution type.

The only exception here is in PHP 7.0 introduced strict type hints. So trying to use them interchangeably with strict type hints on will throw an error

<?php
declare(strict_types=1);
$var = 1; //integer

function foo(string $data) :string {
    echo $data;
}
foo($var);

Produces (demo)

Fatal error: Uncaught TypeError: Argument 1 passed to foo() must be of the type string, integer given, called in /in/Be68h on line 8 and defined in /in/Be68h:5

Comments

4

The hackerrank problem says that you can not use loop or conditions and have to throw an exception if its not an integer. I tried the following code and it worked:

<?php
$handle = fopen ("php://stdin","r");
fscanf($handle,"%s",$S);

set_error_handler("BadString");
function BadString($errno, $errstr, $errfile, $errline)
{
    throw new BadStringException('Bad String');
}


class BadStringException extends Exception { }    

class Numeric extends BadStringException
{
    private $number;
    public function __construct($input)
    {
        $this->number = intval($input);
    }

    public function Display()
    {
        echo ($this->number / $this->number) + ($this->number - 1);
    }
}

try {
    (new Numeric($S))->Display();
} catch (BadStringException $E) {
    echo $E->getMessage();
}

Comments

1

Disclaimer

@Machavity's answer below has a lot more useful information about types in PHP. I've solved a weird problem in a hacky way here, and for the record I would never put this in a piece of software that I'm writing.

Solution

function badString($errno, $errstr, $errfile, $errline) {
  print "Bad String\n";
}

set_error_handler('badString');

function parseString($string) {
  $temp = 1 / ($string + ($string === "0"));
}

Approach

  1. Generate a divide by zero warning if it's a bad string
  2. On the warning, print Bad String

1. Generate warning

If it can't be cast to an integer, $string is 0 when used as an integer (see @CBroe's comment).

If it started as the string "0", then the strong equality operator === will return true for $string === "0".... which evaluates to 1.

So if the input is not a number, then $string is zero and $string === "0" is zero, then 1/0 generates a warning.

 input | $string  | $string === "0"    |   ($string + ($string === "0"))
+=======================================================================+
 foo   |     0    |         0          |               0
 0     |     0    |         1          |               1
 1     |     1    |         0          |               1
 45    |     45   |         0          |               45

2. On warning, print

Borrowed from https://stackoverflow.com/a/3071119/3012550

Comments

1

This is the answer using the delegate, and does not use ternary conditions.

$funcArr = [true=>"intval", false=>function ($s) {return "Bad String";}];
$func = $funcArr[ctype_digit($S)];
echo $func($S);

Comments

1

Another solution for PHP 7 using PHP TypeError exception handling:

function check(int $val) { echo $val; } 
try {
    check($SS);
} catch (TypeError $ex) {
    echo 'Bad String';
}

Comments

0

This works but feels wrong:

<?php
$handle = fopen("php://stdin", "r");
fscanf($handle, "%s", $SS);

$i = (int) is_numeric($SS);
$N = 'a' . $i;

$str = "goto $N;
    a0:
    return new Exception('Bad StringBad String');

    a1:
    return new Exception($SS);
   ";
try {
    throw eval($str);
} catch (Exception $e) {
    echo $e->getMessage();
}

Comments

0

I just encountered this question on HackerRank and was led here by comments there. I got stuck on it for quite a while because their submission tester is very picky and stupid. They check that you don't have the string if anywhere in your code and that you don't use the ternary operator. However, these checks don't span lines, so you can use the ternary if you split it. They also don't actually check for use of exceptions, so you can completely skip that part.

While this solution doesn't explicitly follow the stated rules, it does pass all the tests. And because I'm also a fan of code golfing, it should be the shortest possible working solution. :)

<?=is_numeric($i=fgets(STDIN))?$i
:'Bad String';

Comments

0

My approach to solving it was using intdiv to generate an exception without conditional statements:

try {
    // Convoluted way to throw an integer conversion exception.
    $i1 = intdiv( 1, intval($S . "1") );
    $converted = (int)$S;
    echo "$converted\n";
} catch( DivisionByZeroError $exception ) {
    echo "Bad String\n";
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.