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?

Community
  • 1
  • 1
CrazyCrow
  • 4,125
  • 1
  • 28
  • 39
  • 1
    Nothing built-in, AFAIK. [Casting strings to integers](http://php.net/manual/en/language.types.string.php#language.types.string.conversion) 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. – CBroe Apr 07 '16 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. – Hilmi Erdem KEREN Mar 07 '19 at 16:31

10 Answers10

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.

Razvan
  • 2,436
  • 18
  • 23
  • same question on https://www.hackerrank.com/challenges/30-exceptions-string-to-integer?h_r=next-challenge&h_v=zen. but your answer no pass test case You should use exception handling concepts. – Parnit Das Sep 03 '16 at 14:06
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";
}
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

Machavity
  • 30,841
  • 27
  • 92
  • 100
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();
}
Parminder Singh
  • 351
  • 1
  • 10
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

Community
  • 1
  • 1
alexanderbird
  • 3,847
  • 1
  • 26
  • 35
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);
IvanaGyro
  • 598
  • 7
  • 25
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';
}
aminusia
  • 51
  • 1
  • 6
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();
}
Geodin
  • 21
  • 7
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';
Alex Howansky
  • 50,515
  • 8
  • 78
  • 98
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";
}
mukunda
  • 2,908
  • 15
  • 21