Разделить строку и вернуть объект - PullRequest
0 голосов
/ 06 ноября 2018

Я работаю над инструментом и застрял.

Я обращаюсь к объекту таблицы стилей веб-сайта и хочу получить только «CSSFontFaceRule». Я разработал это, но результат в моем возвращенном объекте - огромная строка. Я хочу разделить строку на объект. Я также создал скрипку: http://jsfiddle.net/9eoytc6v/1/

Это мой статус-кво:

@font-face {font-family: "Test-Book";
src: 
    url("https://fontserver.xyz/test.eot?#iefix") format("embedded-opentype"),
    url("https://fontserver.xyz/test.woff2") format("woff2"),
    url("https://fontserver.xyz/test.woff") format("woff"),
    url("https://fontserver.xyz/test.ttf") format("truetype"),
    url("https://fontserver.xyz/test.svg#Test-Book") format("svg");
}
let fonts = {};

function getFontPairs(obj) {
  let object = obj || {},
    stylesheet = document.styleSheets,
    rule = null,
    length = stylesheet.length,
    j;
  while (0 <= --length) {
    rule = stylesheet[length].rules || stylesheet[length].cssRules || [];
    j = rule.length;
    while (0 <= --j) {
      if (rule[j].constructor.name === "CSSFontFaceRule") {
        let sourcesString = rule[j].style.src;
        let re = /\s*(?:,|$)\s*/;
        let sources = sourcesString.split(re);
        let final = [];

        sources.forEach(function(element){
        let reg = /[ ,]+/;
        let srcArray = element.split(reg);
        srcArray = srcArray.reverse();
        final.push(srcArray);
        });

       object[rule[j].style.fontFamily] = final;


      }
    }
  }
  return object;
}

getFontPairs(fonts);
console.log(fonts);

Я пытался работать с массивами, но мой вывод немного грязный: Текущее решение массива

Вместо этого я хочу достичь чего-то вроде этого: Ожидаемое решение объекта

Так что я не очень хорош в RegEx на данный момент, и я хочу убрать url("") и format(""). Я ценю любую помощь. Может быть, кто-то может помочь с более производительной версией моего кода.

1 Ответ

0 голосов
/ 07 ноября 2018

Просто сопоставьте URL и формат из каждой исходной строки. Подойдет простое регулярное выражение, регулярное выражение просто совпадает с тем, что в двойных или одинарных кавычках, например, регулярное выражение соответствует URL:

/url\(.(.+?).\)/

Что означает совпадение чего-либо между url(. и .). Парень сбежал, чтобы регулярное выражение не смотрело на них как на группу. . (любой символ) для обозначения кавычек (двойных или одинарных). (.+?) - это то, что нас интересует, URL-адрес, он использует режим non-gready ?, чтобы он соответствовал как можно меньшему числу символов, в противном случае вы можете получить URL-адрес, подобный: https://fontserver.xyz/test.eot?#iefix") format("embedded-opentype, который соответствует первой цитате второй (выходит за пределы URL и входит в территорию формата).

Затем, чтобы построить объект, просто reduce источники в один, как:

let sourcesObj = sources.reduce((acc, source) => {       // for each source
  let format = source.match(/format\(.(.+?).\)/)[1],     // get the format
      url = source.match(/url\(.(.+?).\)/)[1];           // and the url

  acc[format] = { format, url };                         // add them to the sourcesObj under the key format ({ format, url } is short for { format: format, url: url })
  return acc;
}, {});

Полный код:

function getFontPairs() {
  let object = {},
    stylesheet = document.styleSheets,
    rule = null,
    length = stylesheet.length,
    j;
  while (0 <= --length) {
    rule = stylesheet[length].rules || stylesheet[length].cssRules || [];
    j = rule.length;
    while (0 <= --j) {
      if (rule[j].constructor.name === "CSSFontFaceRule") {
        let sourcesString = rule[j].style.src;
        let sources = sourcesString.split(/\s*,\s*/);

        let sourcesObj = sources.reduce((acc, source) => {
          let format = source.match(/format\(.(.+?).\)/)[1],
              url = source.match(/url\(.(.+?).\)/)[1];

          acc[format] = { format, url };
          return acc;
        }, {});

        object[rule[j].style.fontFamily] = sourcesObj;
      }
    }
  }
  return object;
}

let fonts = getFontPairs();
console.log(fonts);

Примечание: Более сложной альтернативой URL и регулярному выражению формата будет:

/url(\s*["'](.+?)["']\s*)/

, который обрабатывает случаи, когда есть пробелы, такие как url( "..." ), и ищет кавычки (" или '), чтобы быть безопасными. То же самое можно применить к формату регулярных выражений.


EDIT:

Если в каком-либо источнике отсутствует поле, просто проверьте, действительно ли регулярные выражения формата и URL-адреса соответствуют чему-либо, прежде чем получить доступ к группе [1]:

let sourcesObj = sources.reduce((acc, source) => {
  let format = source.match(/format\(.(.+?).\)/),
      url = source.match(/url\(.(.+?).\)/);

  if(format && url) {                                       // if and only if the two regexes matched what they are intended for
    acc[format[1]] = { format: format[1], url: url[1] };    // add the current source to 'sourcesObj' (notice the '[1]' is used after we've made sure that neither 'format' nor 'url' are 'null')
  }
  return acc;
}, {});

РЕДАКТИРОВАТЬ 2:

Если format отсутствует, заменить на "Unknown":

let sourcesObj = sources.reduce((acc, source) => {
  let format = source.match(/format\(.(.+?).\)/),
      url = source.match(/url\(.(.+?).\)/)[1];

  format = format? format[1]: "Unknown";

  acc = { format, url };
  return acc;
}, {});
...