Differentiate among comparable values through placement regex

I'm currently tackling a challenge involving regex as I work on breaking down shorthand CSS code for the font property. Here is my progress thus far:

var style = decl.val.match(/\s*(?:\s*(normal|italic|oblique)){1}/i); style = style ? style[1] : "";
var variant = decl.val.match(/\s*(?:\s*(normal|small-caps))/i); variant = variant ? variant[1] : "";
var weight = decl.val.match(/\s*((?:\s*(?:normal|bold|bolder|lighter|\d+(?:\%|in|cm|mm|em|rem|ex|pt|pc|px))){1})/i); weight = weight ? weight[1] : "";
var size = decl.val.match(/\/\s*((?:\s*(?:xx-small|x-small|small|medium|large|x-large|xx-large|larger|smaller|\d+(?:\%|in|cm|mm|em|rem|ex|pt|pc|px))){1,2})/i); size = size ? size[1] : "";
var height = decl.val.match(/\s*(?:\s*(normal|inherit|\d+(?:\%|in|cm|mm|em|rem|ex|pt|pc|px))){1}/i); height = height ? height[1] : "";
var family = decl.val.match(/\s*(?:\s*([a-zA-Z\-\,\'\"\s]+))(?:,|;)/i); family = family ? family[1] : "";
var values = decl.val.match(/\s*(?:\s*(caption|icon|menu|message-box|small-caption|status-bar)){1}/i); values = values ? values[1] : "";

While everything is running smoothly, there's an issue when using this specific string:

font: normal small-caps 120%/120% fantasy, sans-serif;

This results in style, variant, weight, and height all being set to "normal":

style --> "normal"
variant --> "normal"
weight --> "normal"
height --> "normal"

The problem lies with the regex matching the first instance without verifying if another value should be taken instead. The desired outcome should look like this:

style --> "normal"
variant --> "small-caps"
weight --> "120%"
height --> 

If you have any questions or need further clarification, please don't hesitate to ask. Thank you for your assistance!

Answer №1

There seems to be a minor issue with the forward slash placement between weight and sizes. To resolve this, consider combining into one regex pattern where everything except anchors is optional. This will help align things properly to avoid 'normal' appearing on most variables.

Edit I came across a reference that details how CSS Font Shorthand Property parsing works: http://www.w3schools.com/cssref/pr_font_font.asp

edit2 The hard spaces delimiters have been adjusted to come after the optional parts and between the required parts.

 #  /(?:(?:(normal|italic|oblique|initial|inherit)\s+)?(?:(normal|small-caps|initial|inherit)\s+)?(?:((?:normal|bold|bolder|lighter|initial|inherit|\d+))\s+)?(?:(smaller|small|x-small|xx-small|medium|larger|large|x-large|xx-large|initial|inherit|\d+(?:\%|in|cm|mm|em|rem|ex|pt|pc|px))(?:\/(normal|initial|inherit|\d+(?:\%|in|cm|mm|em|rem|ex|pt|pc|px)))?\s+)(?:(initial|inherit|(?:"[^"]*"|'[^']*'|[a-zA-Z-]+)(?:\s*,\s*(?:"[^"]*"|'[^']*'|[a-zA-Z-]+))*))|(caption|icon|menu|message-box|small-caption|status-bar|initial|inherit))/

 ####  CSS - Font Shorthand Property  
 ####  Reference:  http://www.w3schools.com/cssref/pr_font_font.asp    
 #### --------------------------------
 #### font:     

 (?:
      #### User Defined Fonts
      #### ------------------

      ##### Style (optional)
      (?:
           (                        # (1 start), Style
                normal
             |  italic
             |  oblique
             |  initial
             |  inherit 
           )                        # (1 end)
           \s+   # delimiter
      )?

      ##### Variant (optional)
      (?:
           (                        # (2 start), Variant
                normal
             |  small-caps
             |  initial
             |  inherit 
           )                        # (2 end)
           \s+   # delimiter
      )?

      ##### Weight (optional)
      (?:
           (                        # (3 start), Weight
                (?:
                     normal
                  |  bold
                  |  bolder
                  |  lighter
                  |  initial
                  |  inherit 
                  |  \d+ 
                )
           )                        # (3 end)
           \s+   # delimiter
      )?

      ##### Size (required)
      (?:
           (                        # (4 start), Size
                smaller
             |  small
             |  x-small
             |  xx-small
             |  medium
             |  larger
             |  large
             |  x-large
             |  xx-large
             |  initial
             |  inherit
             |  \d+ 
                (?: \% | in | cm | mm | em | rem | ex | pt | pc | px )
           )                        # (4 end)

           #####  Line Height (optional)
           (?:
                /                   # Separator
                (                   # (5 start), Line height
                     normal
                  |  initial
                  |  inherit
                  |  \d+ 
                     (?: \% | in | cm | mm | em | rem | ex | pt | pc | px )
                )                   # (5 end)

           )?

           \s+   # delimiter 
      )

      ##### Family (required)
      (?:
           (                        # (6 start), Family
                initial
             |  inherit
             |  (?: " [^"]* " | ' [^']* ' | [a-zA-Z-]+ )
                (?:
                     \s* , \s* 
                     (?: " [^"]* " | ' [^']* ' | [a-zA-Z-]+ )
                )*
           )                        # (6 end)
      )

   |  

      #### OR, 
      #### Use the Fonts used by these OS elements
      #### ------------------

      #### Values (required, if used)
      (                             # (7 start), Use values
           caption
        |  icon
        |  menu
        |  message-box
        |  small-caption
        |  status-bar
        |  initial
        |  inherit
      )                             # (7 end)
 )

Perl Test case

$str = 'font:normal small-caps 120%/120% "Times New Roman", sans-serif;';

if ( $str =~ /(?:(?:(normal|italic|oblique|initial|inherit)\s+)?(?:(normal|small-caps|initial|inherit)\s+)?(?:((?:normal|bold|bolder|lighter|initial|inherit|\d+))\s+)?(?:(smaller|small|x-small|xx-small|medium|larger|large|x-large|xx-large|initial|inherit|\d+(?:\%|in|cm|mm|em|rem|ex|pt|pc|px))(?:\/(normal|initial|inherit|\d+(?:\%|in|cm|mm|em|rem|ex|pt|pc|px)))?\s+)(?:(initial|inherit|(?:"[^"]*"|'[^']*'|[a-zA-Z-]+)(?:\s*,\s*(?:"[^"]*"|'[^']*'|[a-zA-Z-]+))*))|(caption|icon|menu|message-box|small-caption|status-bar|initial|inherit))/)
{
    print "\nmatched  '$&'\n\n";
    print "style   = '$1'\n";
    print "variant = '$2'\n";
    print "weight  = '$3'\n";
    print "size    = '$4'\n";
    print "height  = '$5'\n";
    print "family  = '$6'\n";
    print "values  = '$7'\n";
}

Output >>

matched  'normal small-caps 120%/120% "Times New Roman", sans-serif'

style   = 'normal'
variant = 'small-caps'
weight  = ''
size    = '120%'
height  = '120%'
family  = '"Times New Roman", sans-serif'
values  = ''

Answer №2

Here is a method you can use to manipulate attributes in a string:

Start by identifying one attribute and then removing it from the original string. Proceed to search for the next attribute in the updated string.

Below is an illustration focusing on the primary attribute within the string:

var str = decl.val;

function removeFromString(str, result) {
    console.log(result);
    return str.slice(0, result.index) + str.slice(result.index + result[0].length);
}

var style = str.match(/\s*(?:\s*(normal|italic|oblique)){1}/i); 
if(style) {
    str = removeFromString(str, style);
}
style = style ? style[1] : "";

To visualize this process, I have created a JSFiddle.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using AJAX to assign PHP session variables

Is there a way to update the SESSION variable named "fullname" on Page 2 without causing the page to refresh? This is my attempt using AJAX: HTML code for Page 1: <input type="text" name="fullname" id="fullname" placeholder="Full name"> <butto ...

What is the reasoning behind exporting it in this manner in the index file?

As I was going through a tutorial about nests, there was this step where the instructor made a folder named "dtos" and inside it, they created two dto files (create-user.dto and edit-user.dto). Following that, they also added an index file in the same fold ...

Error: The operation 'join' cannot be performed on an undefined value within Fast2sms

I am encountering issues while attempting to send SMS using fast2sms in Node.js. The error message reads as follows: TypeError: Cannot read property 'join' of undefined at Object.sendMessage (C:\Users\user\Desktop\node_module ...

Create a Vue slot layout that mirrors the structure of Material UI

This is the code I have been working on: <tr :key="index" v-for="(item, index) in items"> <td v-for="header in headers" :key="header.value"> {{ item[header.value] }} </td> <td> & ...

What is the process for importing an md file in a create-react-app project using JavaScript?

Attempting to execute the blog example provided on Material UI's getting started page. However, encountering an issue with the source code: Inside blog.js import post1 from './blog-post.1.md'; . . . return( <Main>{post1}<Main/> ...

Issue with the Dropdown menu in Metro UI CSS - not functioning properly

I have integrated the METRO UI CSS into my project and created a dropdown menu. The design looks great, but unfortunately, the dropdown list is not appearing as expected. To implement this feature, I followed the example provided on the following link: H ...

Deliver search findings that are determined by matching criteria, rather than by identification numbers

I am seeking to return a JSON match upon form submission, rather than simply searching for a specific ID. However, I am uncertain about how to structure this. I have the ability to search for the necessary match in a JavaScript document within one of my n ...

Let's talk about the CSS properties for centering content and automatically

I've been struggling with getting my navbar to center and adjust its width based on the content inside. Can anyone help me with this? <nav> <ul id="menu" class="black"> <li><a href="index.html">Home</a></l ...

Executing a function within a worker thread in Node.js

This is the worker I am using: const Worker = require('worker_threads'); const worker = new Worker("function hello () { console.log('hello world');}", { eval: true }) worker.hello() // this is incorrect I want to invoke the hello() fu ...

Having trouble retrieving information from the local API in React-Native

Currently, I have a web application built using React and an API developed in Laravel. Now, I am planning to create a mobile app that will also utilize the same API. However, I'm encountering an issue where I cannot fetch data due to receiving the err ...

Adjusting Position for Parallax Effect using Jquery

I am currently experimenting with a basic Scrolldeck Jquery Parallax effect to scroll items at varying speeds. However, I am encountering some difficulties in making items move from top to bottom. In the example provided below, you will see a shoe moving f ...

The file upload issue with FormData append in CodeIgniter is causing errors

My current challenge involves uploading files using AJAX to my CodeIgniter based website. Unfortunately, I am encountering an issue where I cannot retrieve the file field value in the controller. This results in an error message stating "Undefined index: & ...

Switching the theme color from drab grey to vibrant blue

How can I change the default placeholder color in md-input-container from grey to Material Blue? I have followed the instructions in the documentation and created my own theme, but none of the code snippets seems to work. What am I doing wrong? mainApp. ...

What is the best way to apply a hover effect to a specific element?

Within my CSS stylesheet, I've defined the following: li.sort:hover {color: #F00;} All of my list items with the 'sort' class work as intended when the Document Object Model (DOM) is rendered. However, if I dynamically create a brand new ...

Is there a way to deactivate a div in Blazor when clicking outside of the div?

Is it possible to have two divs on a single page, where one appears on the right side and the other on the left side? Is there a way to close or hide the left side div whenever we click on the right side div? ...

What is the best way to add randomness to the background colors of mapped elements?

I am looking for a way to randomly change the background color of each element However, when I try to implement it in the code below, the background color ends up being transparent: { modules.map((module, index) => ( <div className='carou ...

the spillage exhibits only a thin streak of gray

My website is primarily a Single Page Website, however, there are specific pages that can only be accessed by registered users. On the website, there is a section referred to as a "block" where you will find a button labeled "Login / Register". Upon clicki ...

Finding the correlation between SVG element IDs and JSON keysUnderstanding how to pair up

Currently, I have an SVG file that can be viewed here. My goal is to present specific data when elements within the SVG are clicked. The data is in JSON format and I am looking to match each ID of an SVG element with a key in the JSON data. If both the key ...

Enhance your slideshows with React-slick: Integrate captivating animations

I recently built a slider using react slick, and now there is a need to adjust the transition and animation of slides when the previous and next buttons are clicked. I received some advice to add a class to the currently active slide while changing slide ...

React- hiding div with hover effect not functioning as expected

I'm having trouble using the :hover feature in CSS to control the display of one div when hovering over another, it's not functioning as expected. I've successfully implemented this on other elements, but can't seem to get it right in t ...