Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
34 / 34 |
|
100.00% |
5 / 5 |
CRAP | |
100.00% |
1 / 1 |
SizeParser | |
100.00% |
34 / 34 |
|
100.00% |
5 / 5 |
10 | |
100.00% |
1 / 1 |
toByte | |
100.00% |
16 / 16 |
|
100.00% |
1 / 1 |
5 | |||
parse | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
2 | |||
validParse | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
makeParseException | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
makeRegexPattern | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | /** |
4 | * @license MIT |
5 | * @author hazuki3417<hazuki3417@gmail.com> |
6 | * @copyright 2023 hazuki3417 all rights reserved. |
7 | */ |
8 | |
9 | namespace Selen\Str; |
10 | |
11 | use InvalidArgumentException; |
12 | |
13 | /** |
14 | * string型で表現されたデータ量をint型へ変換するクラスです。 |
15 | */ |
16 | class SizeParser |
17 | { |
18 | /** @var string[] SI接頭辞 */ |
19 | public const UNIT_SI_PREFIX = ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB', 'RB', 'QB']; |
20 | /** @var string[] 2進接頭辞 */ |
21 | public const UNIT_BINARY_PREFIX = ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB', 'RiB', 'QiB']; |
22 | /** @var string[] その他の接頭辞 */ |
23 | public const UNIT_OTHER_PREFIX = ['byte']; |
24 | |
25 | /** |
26 | * string型で表現されたデータ量をbyte単位に変換します |
27 | * |
28 | * @param string $value 文字列を渡します |
29 | * |
30 | * @return int|float byte数を返します |
31 | */ |
32 | public static function toByte(string $value) |
33 | { |
34 | [ |
35 | 'value' => $value, |
36 | 'unit' => $tmpUnit, |
37 | ] = self::parse($value); |
38 | $unit = \strtolower($tmpUnit); |
39 | |
40 | if ($unit === 'byte') { |
41 | // byte指定のみ |
42 | return $value; |
43 | } |
44 | |
45 | $radix = \strpos($unit, 'i') === false ? 1000 : 1024; |
46 | $scanChars = ['k', 'm', 'g', 't', 'p', 'e', 'z', 'y', 'r', 'q']; |
47 | $selectIndex = 0; |
48 | |
49 | foreach ($scanChars as $index => $scanChar) { |
50 | if (\strpos($unit, $scanChar) === false) { |
51 | continue; |
52 | } |
53 | $selectIndex = $index + 1; |
54 | break; |
55 | } |
56 | return $value * pow($radix, ($selectIndex)); |
57 | } |
58 | |
59 | /** |
60 | * string型で表現されたデータ量を値と単位に分割します |
61 | * |
62 | * @param string $value 文字列を渡します |
63 | * |
64 | * @throws InvalidArgumentException パースに失敗したときの例外をスローします |
65 | * |
66 | * @return array<string,int|string> 文字列表現されたデータ量を値と単位に分割した配列を返します |
67 | */ |
68 | public static function parse(string $value) |
69 | { |
70 | $pattern = self::makeRegexPattern(); |
71 | |
72 | if (preg_match($pattern, $value, $matches)) { |
73 | [1 => $value,2 => $unit] = $matches; |
74 | |
75 | return [ |
76 | 'value' => (int) $value, |
77 | 'unit' => $unit, |
78 | ]; |
79 | } |
80 | throw self::makeParseException(); |
81 | } |
82 | |
83 | /** |
84 | * string型で表現されたデータ量フォーマットが正しいか検証します |
85 | * |
86 | * @param string $value 文字列を渡します |
87 | * |
88 | * @return bool 正しい場合はtrueを、それ以外の場合はfalseを返します |
89 | */ |
90 | public static function validParse(string $value): bool |
91 | { |
92 | return \preg_match(self::makeRegexPattern(), $value); |
93 | } |
94 | |
95 | /** |
96 | * string型で表現されたデータ量フォーマットのパースに失敗したときの例外をスローします |
97 | * |
98 | * @return InvalidArgumentException パースに失敗したときの例外をスローします |
99 | */ |
100 | public static function makeParseException() |
101 | { |
102 | $format = 'Invalid data format. Expected format %s .'; |
103 | $mes = \sprintf($format, self::makeRegexPattern()); |
104 | return new InvalidArgumentException($mes); |
105 | } |
106 | |
107 | /** |
108 | * string型で表現されたデータ量フォーマットをパースする正規表現パターンを作成します |
109 | * |
110 | * @return string 正規表現パターンを返します |
111 | */ |
112 | private static function makeRegexPattern(): string |
113 | { |
114 | $allowUnits = \array_merge( |
115 | self::UNIT_SI_PREFIX, |
116 | self::UNIT_BINARY_PREFIX, |
117 | self::UNIT_OTHER_PREFIX, |
118 | ); |
119 | return \sprintf('/^(\d+)(%s)$/', \implode('|', $allowUnits)); |
120 | } |
121 | } |