21

文字列をチェックしてISBN-10またはISBN-13(ブックID)があるかどうかを確認するIf-elseステートメントがあります。

私が直面している問題は、ISBN-13チェックの前に発生するISBN-10チェックにあります。ISBN-10チェックは10文字以上のものと一致するため、ISBN-13をISBN-10と間違える可能性があります。

ここにコードがあります...

$str = "ISBN:9780113411436";

if(preg_match("/\d{9}(?:\d|X)/", $str, $matches)){
   echo "ISBN-10 FOUND\n";  
   //isbn returned will be 9780113411
   return 0;
}

else if(preg_match("/\d{12}(?:\d|X)/", $str, $matches)){
   echo "ISBN-13 FOUND\n";
   //isbn returned will be 9780113411436
   return 1;
}

この問題を確実に回避するにはどうすればよいですか?

4

5 に答える 5

41

これには、正規表現が 1 つだけ必要です。次に、より効率的なstrlen()チェックを行って、どれが一致したかを確認します。以下は、ハイフンの有無にかかわらず、オプションで文字列ISBN:,ISBN:(space)またはISBN(space).

ISBN の検索 :

function findIsbn($str)
{
    $regex = '/\b(?:ISBN(?:: ?| ))?((?:97[89])?\d{9}[\dx])\b/i';

    if (preg_match($regex, str_replace('-', '', $str), $matches)) {
        return (10 === strlen($matches[1]))
            ? 1   // ISBN-10
            : 2;  // ISBN-13
    }
    return false; // No valid ISBN found
}

var_dump(findIsbn('ISBN:0-306-40615-2'));     // return 1
var_dump(findIsbn('0-306-40615-2'));          // return 1
var_dump(findIsbn('ISBN:0306406152'));        // return 1
var_dump(findIsbn('0306406152'));             // return 1
var_dump(findIsbn('ISBN:979-1-090-63607-1')); // return 2
var_dump(findIsbn('979-1-090-63607-1'));      // return 2
var_dump(findIsbn('ISBN:9791090636071'));     // return 2
var_dump(findIsbn('9791090636071'));          // return 2
var_dump(findIsbn('ISBN:97811'));             // return false

これは、指定された文字列を検索して、可能性のある ISBN-10 値 ( を返す1) または ISBN-13 値 ( を返す2) が含まれているかどうかを確認します。そうでない場合は、 が返されfalseます。

上記のデモを参照してください。


ISBN の検証:

厳密な検証のために、ISBNのウィキペディアの記事には、 ISBN-10およびISBN-13の PHP 検証関数がいくつかあります。以下は、上記の関数のわずかに変更されたバージョンに対して使用するために、コピー、整理、および変更された例です。

return ブロックを次のように変更します。

    return (10 === strlen($matches[1]))
        ? isValidIsbn10($matches[1])  // ISBN-10
        : isValidIsbn13($matches[1]); // ISBN-13

ISBN-10 の検証:

function isValidIsbn10($isbn)
{
    $check = 0;

    for ($i = 0; $i < 10; $i++) {
        if ('x' === strtolower($isbn[$i])) {
            $check += 10 * (10 - $i);
        } elseif (is_numeric($isbn[$i])) {
            $check += (int)$isbn[$i] * (10 - $i);
        } else {
            return false;
        }
    }

    return (0 === ($check % 11)) ? 1 : false;
}

ISBN-13 の検証:

function isValidIsbn13($isbn)
{
    $check = 0;

    for ($i = 0; $i < 13; $i += 2) {
        $check += (int)$isbn[$i];
    }

    for ($i = 1; $i < 12; $i += 2) {
        $check += 3 * $isbn[$i];
    }

    return (0 === ($check % 10)) ? 2 : false;
}

上記のデモを参照してください。

于 2012-12-31T00:24:25.387 に答える
3

とを使用^$て、文字列の最初と最後を一致させます。文字列区切り文字を使用することにより、10桁または13桁のコードをテストする順序は重要ではありません。

10桁

/^ISBN:(\d{9}(?:\d|X))$/

13桁

/^ISBN:(\d{12}(?:\d|X))$/

注: http: //en.wikipedia.org/wiki/International_Standard_Book_Numberによると、ISBNにもが含まれているように見え-ます。ただし、使用しているものに基づいて、$str10桁または13桁をチェックする前にハイフンを削除したように見えます。

追記: ISBNの最後の桁は前の桁の一種のチェックサムとして使用されるため、正規表現だけではISBNが有効なものであることを検証できません。10桁または13桁のフォーマットしかチェックできません。


$isbns = array(
  'ISBN:1234567890',       // 10-digit
  'ISBN:123456789X',       // 10-digit ending in X
  'ISBN:1234567890123',    // 13-digit
  'ISBN:123456789012X',    // 13-digit ending in X
  'ISBN:1234'              // invalid
);

function get_isbn($str) {
   if (preg_match('/^ISBN:(\d{9}(?:\d|X))$/', $str, $matches)) {
      echo "found 10-digit ISBN\n";
      return $matches[1];
   }
   elseif (preg_match('/^ISBN:(\d{12}(?:\d|X))$/', $str, $matches)) {
      echo "found 13-digit ISBN\n";
      return $matches[1];
   }
   else {
      echo "invalid ISBN\n";
      return null;
   }
}

foreach ($isbns as $str) {
   $isbn = get_isbn($str);
   echo $isbn."\n\n";
}

出力

found 10-digit ISBN
1234567890

found 10-digit ISBN
123456789X

found 13-digit ISBN
1234567890123

found 13-digit ISBN
123456789012X

invalid ISBN
于 2012-12-30T23:32:24.847 に答える
1

ブロックの順序を切り替え、if elseISBNからすべての空白、コロン、およびハイフンを削除します。

//Replace all the fluff that some companies add to ISBNs
$str = preg_replace('/(\s+|:|-)/', '', $str);

if(preg_match("/^ISBN\d{12}(?:\d|X)$/", $str, $matches)){
   echo "ISBN-13 FOUND\n";
   //isbn returned will be 9780113411436
   return 1;
}

else if(preg_match("/^ISBN\d{9}(?:\d|X)$/", $str, $matches)){
   echo "ISBN-10 FOUND\n";  
   //isbn returned will be 9780113411
   return 0;
}
于 2012-12-30T23:32:58.687 に答える
1

ISBN-10チェックの前にISBN-13チェックを入れますか?これは、任意の文字列の一部としてそれらを一致させることを前提としています。つまり、(例では最初に余分な「ISBN:」があるため、文字列内の任意の場所で一致させることが何らかの要件のようです)

于 2012-12-30T23:32:59.427 に答える
0
ISBN10_REGEX = /^(?:\d[\ |-]?){9}[\d|X]$/i
ISBN13_REGEX = /^(?:\d[\ |-]?){13}$/i
于 2016-08-11T07:46:49.540 に答える