Я пытаюсь написать функцию, которая будет принимать цвет RGB (A) и сохранять его значения в массиве, с возможностью исключить альфа-значение. У меня возникают проблемы с выяснением, как написать регулярное выражение, которое будет соответствовать входным данным, но я думаю, что что-то вроде этого — то, что я ищу:
function rgb_array( $color, $include_alpha = true ) {
$pattern = 'what goes here?';
$color = preg_match( $pattern, $color, $matches);
if ( $include_alpha == true && ! empty( $matches[4] ) ) {
$color = array( $matches[1], $matches[2], $matches[3], $matches[4] );
} else {
$color = array( $matches[1], $matches[2], $matches[3] );
}
return $color;
}
Я хотел бы иметь возможность кормить его любой допустимой формой rgb / rgba:
rgb(0,0,0)
rgb(00,00,00)
rgb(0, 0, 0)
rgb(00, 00, 00)
rgba(0,0,0,0.5)
rgba(255, 255, 255, 1)
etc...
И пусть он производит массив:
[0] => '00', // red
[1] => '00', // green
[2] => '00', // blue
[3] => '1' // alpha only included if available and desired.
На данный момент я могу сделать это через str_replace
:
$color = 'rgb(12, 14, 85)';
$remove = array( 'rgb', 'a', '(', ')', ' ' );
$color = str_replace( $remove, '', $color );
$color = explode( ',', $color );
Но это кажется хакерским, и я не могу найти хороший способ опционально включить / исключить альфа.
Спасибо за вашу помощь, и если есть совершенно другой подход, чем preg_match
это было бы лучше, я все уши.
Мой ответ не только извлечет значения подстроки, которые вы хотите, но и дополнительно обеспечит достаточно высокий уровень проверки (а не 100% -ную проверку). Я изменил шаблон из https://stackoverflow.com/a/31245990/2943403 точнее ответить на этот вопрос. Я надеюсь, что вы найдете этот ответ точным, элегантным и прямым.
Если вы хотите сократить / упростить шаблон, это будет делать: (Regex101 Demo)
~^rgba?\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([.\d]+))?\)$~
Код: (Демо w / $ include_alpha = true) (Демо w / $ include_alpha = false) (Regex101 Demo)
function rgb_array($color, $include_alpha = true) {
$pattern = '~^rgba?\((25[0-5]|2[0-4]\d|1\d{2}|\d\d?)\s*,\s*(25[0-5]|2[0-4]\d|1\d{2}|\d\d?)\s*,\s*(25[0-5]|2[0-4]\d|1\d{2}|\d\d?)\s*(?:,\s*([01]\.?\d*?))?\)$~';
if (!preg_match($pattern, $color, $matches)) {
return []; // disqualified / no match
}
return array_slice($matches, 1, $include_alpha ? 4 : 3);
}
$strings = [
'rgb(0,0,0)',
'rgb(00,00,00)',
'rgb(0, 0, 0)',
'donkey eggs',
'rgb(00, 00, 00)',
'rgba(0,0,0,0.5)',
'rgba(255, 255, 255, 1)'
];
foreach ($strings as $string) {
echo "Process: $string\n";
var_export(rgb_array($string));
echo "\n";
}
Выход:
Process: rgb(0,0,0)
array (
0 => '0',
1 => '0',
2 => '0',
)
Process: rgb(00,00,00)
array (
0 => '00',
1 => '00',
2 => '00',
)
Process: rgb(0, 0, 0)
array (
0 => '0',
1 => '0',
2 => '0',
)
Process: donkey eggs
array (
)
Process: rgb(00, 00, 00)
array (
0 => '00',
1 => '00',
2 => '00',
)
Process: rgba(0,0,0,0.5)
array (
0 => '0',
1 => '0',
2 => '0',
3 => '0.5',
)
Process: rgba(255, 255, 255, 1)
array (
0 => '255',
1 => '255',
2 => '255',
3 => '1',
)
постскриптум Если вы хотите использовать preg_split()
Вы можете быть гораздо менее конкретным в отношении своего паттерна. Вот вам одна строчка (демонстрация)
function rgb_array($color, $include_alpha = true) {
return array_slice(preg_split('~[^\d.]+~', $color, -1, PREG_SPLIT_NO_EMPTY), 0, $include_alpha + 3);
}
Если вам нужно решение для регулярных выражений, вот оно:
rgba?\((\s?\d+),(\s?\d+),(\s?\d+)(?:,\s?(\d+(?:\.\d+)?))?\)
Это соответствует 'rgb'
в начале, затем необязательный 'a'
и левый parenthes
затем он создает 3 одинаковые группы, соответствующие оптиналу белому Space
сопровождаемый одним или несколькими digits
, Четвертая группа является необязательной и соответствует одному или нескольким digits
с последующим dot
и один или несколько digits
,
Цвета будут в индексах 1, 2, 3 и 4 (при наличии).
Вы могли бы использовать preg_split
разделить строку на составные части. Регулярное выражение разбивает строку в одном из ведущих rgba(
, ,
или отставая )
, PREG_SPLIT_NO_EMPTY
Флаг используется, чтобы избежать пустых значений в выходном массиве.
$strings = array('rgb(0,0,0)',
'rgb(00,00,00)',
'rgb(0, 0, 0)',
'rgb(00, 00, 00)',
'rgba(0,0,0,0.5)',
'rgba(255, 255, 255, 1)');
foreach ($strings as $string) {
print_r(preg_split('/rgba?\(\s*|\s*,\s*|\s*\)/', $string, -1, PREG_SPLIT_NO_EMPTY));
}
Выход:
Array
(
[0] => 0
[1] => 0
[2] => 0
)
Array
(
[0] => 00
[1] => 00
[2] => 00
)
Array
(
[0] => 0
[1] => 0
[2] => 0
)
Array
(
[0] => 00
[1] => 00
[2] => 00
)
Array
(
[0] => 0
[1] => 0
[2] => 0
[3] => 0.5
)
Array
(
[0] => 255
[1] => 255
[2] => 255
[3] => 1
)
Немного улучшилось explode
решение:
function rgb_array($color, $include_alpha = true)
{
$color = trim($color, 'rgba()'); # "rgba(255, 255, 255, 1)" => "255, 255, 255, 1"$color = str_replace(' ', '', $color); # "255, 255, 255, 1" => "255,255,255,1"$color = explode(',', $color); # "255,255,255,1" => ["255", "255", "255", "1"]
$color[] = 1; # add extra value to be sure that all parsed colors have transparency
return array_slice($color, 0, 3 + $include_alpha); # length is 3 or 4, depends on $include_alpha value
}
Вы также можете извлечь числа из строки, основываясь на том факте, что встроенный тип PHP приведен к float
а также int
удаляет лишние символы из строки:
function rgb_array($color, $include_alpha = true)
{
$array = array_map('floatval', explode(',', $color));
$array[] = 1;
return array_slice($array, 0, 3 + $include_alpha);
}