简体   繁体   中英

PHP preg_match_all regular expression to get pixel values (with “px”) from css

I'm looking for a regular expression for use with PHP's preg_match_all() function, which will give me all of the px values from a CSS file.

For example, if the css below is used, then the expected result would be an array of:

array ( "11px", "0.45px", "11.0005px", "1.1px", "888.888px" )

The $pattern string is what I have so far -- it doesn't appear to work, however.

The logic I was trying to use is: the number before the decimal can be up to 4 digits, the decimal symbol is optional, and the number after the decimal is optional, up to 4 digits, followed by "px".

$pattern = "/([0-9]{1,4}\.*[0-9]{1,4}*px)/";

$css = '
.some_class {
    font-size: 11px;
    margin-left: 0.45px;
    margin-top:11.0005px;
    border: 1.1px solid blue;
}
.another_class {
    background: rgba(0, 0, 0, 0.2);
    width: 100%;
    color: #012345;
    z-index: 12;
    font-size: calc(100% + 888.888px);
}
';
preg_match_all($pattern, $css, $matches, PREG_PATTERN_ORDER);
  • a capture group is unnecessary and will only slow down the regex engine.
  • \\b will ensure that only full qualifying numbers are matched
  • \\d is a shorter syntax for [0-9] .
  • to match zero or one of something use ? . * means zero or more.
  • since not all pixel values are floats ( 11px ), you can make the decimal place digits and trailing one to four digits optional by wrapping in a non-capturing group and adding a zero or one quantifier ( ? ).
  • your pattern was breaking because you used two consecutive quantifiers: {1,4}* which is like saying "match 1 to 4 0 or more occurrences". The regex engine was like: "huh?"

Code: ( Demo ) ( Pattern Demo )

$css = '
.some_class {
    font-size: 11px;
    margin-left: 0.45px;
    margin-top:11.0005px;
    border: 1.1px solid blue;
}
.another_class {
    background: rgba(0, 0, 0, 0.2);
    width: 100%;
    color: #012345;
    z-index: 12;
    font-size: calc(100% + 888.888px);
}';
$pattern = "/\b\d{1,4}(?:\.\d{1,4})?px/";

var_export(preg_match_all($pattern, $css, $matches) ? $matches[0] : 'fail');

Output:

array (
  0 => '11px',
  1 => '0.45px',
  2 => '11.0005px',
  3 => '1.1px',
  4 => '888.888px',
)

Patterns with greater validation:

  • Checks that the 1-4 digit number is preceded by a colon or a space ( \\K restarts the fullstring match):

     /[: ]\\K\\d{1,4}(?:\\.\\d{1,4})?px/ 
  • Checks that the 1-4 digit number is not preceded by a digit:

     /\\D\\K\\d{1,4}(?:\\.\\d{1,4})?px/ 

Your sample input uses zeros before decimal points. If the zeros are optional, my pattern will need adjusting. These will allow floats without a leading digit while requiring that dot is trailed by a digit.

  1. /\\D\\K(?:\\d{1,4}|\\d{0,4}\\.\\d{1,4})px/

  2. /\\D\\K\\d{0,4}(?:\\.(?=\\d))?\\d{1,4}px/

Just made correction from your pattern,

$pattern = "~([0-9]{1,4})px|([0-9]{1,4}?\.[0-9]{1,4})px~";

$css = '
.some_class {
    font-size: 11px;
    margin-left: 0.45px;
    margin-top:11.0005px;
    border: 1.1px solid blue;
}
.another_class {
    background: rgba(0, 0, 0, 0.2);
    width: 100%;
    color: #012345;
    z-index: 12;
    font-size: calc(100% + 888.888px);
}
';
preg_match_all($pattern, $css, $matches, PREG_PATTERN_ORDER);

Data in $matches :

array (
  0 => 
  array (
    0 => '11px',
    1 => '0.45px',
    2 => '11.0005px',
    3 => '1.1px',
    4 => '888.888px',
  ),
  1 => 
  array (
    0 => '11',
    1 => '',
    2 => '',
    3 => '',
    4 => '',
  ),
  2 => 
  array (
    0 => '',
    1 => '0.45',
    2 => '11.0005',
    3 => '1.1',
    4 => '888.888',
  ),

)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM