从字符串中提取泛型类型参数

时间:2019-03-27 16:59:34

标签: javascript regex

我想创建一个从类型定义(作为纯字符串)中提取“泛型类型参数”的函数。

它应该像这样输入字符串:

Foo<Bar, Baz<Qux>>

并返回具有引用类型+泛型的对象,就像这样(当然,不必严格按照这种确切的格式,只要我可以检索所需的信息即可):

{
   "name": "Foo",
   "generics": [
      {
         "name": "Bar",
         "generics": []
      },

      {
         "name": "Baz",
         "generics": [
            {
               "name": "Qux",
               "generics": []
            }
         ]
      }
   ]
}

我的猜测是将String.match与正则表达式一起使用,例如/<.*>/g,用逗号分隔结果作为定界符,然后递归解析每个参数的泛型。但是,我觉得这太复杂了,我想念的还有一种更简单的方法。

3 个答案:

答案 0 :(得分:1)

最简单的方法是递归构建键映射结构,然后将其转换为树。

下面的keyMapToTree函数使用称为keyMapToTreeInner的内部帮助函数。

console.log(keyMapToTree(parseAsKeyMap('Foo<Bar, Baz<Qux>>')));

function parseAsKeyMap(input, tree = {}) {
  input = input.trim();
  let startIndex = input.indexOf('<'),
    endIndex   = input.lastIndexOf('>');
  if (startIndex !== -1 && endIndex === -1) {
    throw new Error("Missing closing bracket '>' for " + input);
  } else if (startIndex === -1 && endIndex !== -1) {
    throw new Error("Missing opening bracket '<' for " + input);
  } else if (startIndex !== -1 && endIndex !== -1) {
    let head = input.substring(0, startIndex),
      tail = input.substring(startIndex + 1, endIndex);
    tree[head] = {};
    tail.split(/\s*,\s*/).forEach(token => parseAsKeyMap(token, tree[head]));
  } else {
    tree[input] = {};
  }
  return tree;
}

function keyMapToTree(input) {
  let keys = Object.keys(input);
  if (keys.length !== 1) {
    throw new Error('Object must be non-null and have only one key!');
  }
  let key = keys[0], node = { name: key, generics: [] };
  keyMapToTreeInner(input[key], node.generics);
  return node;
}

function keyMapToTreeInner(input, nodeArray) {
  Object.keys(input).map(key => {
    let node = { name: key, generics: [] };
    keyMapToTreeInner(input[key], node.generics);
    nodeArray.push(node)
  });
}
.as-console-wrapper {
  top: 0;
  max-height: 100% !important;
}
<!--

The initial key-map will look like this, so convert this structure to a tree.

{
  "Foo": {
    "Bar": {},
    "Baz": {
      "Qux": {}
    }
  }
}

-->

答案 1 :(得分:0)

如果您是Chrome用户,则此代码可在控制台中运行:

SELECT  DISTINCT                                                             ?pl  
                                                                             ?pl_label 
                                                                             ?abstract 
                                                                             ?_thumbnail
        ( group_concat ( DISTINCT ?_influenced_label   ; separator="; " ) AS ?influenced )
        ( group_concat ( DISTINCT ?_influencedBy_label ; separator="; " ) AS ?influencedBy ) 
        ( group_concat ( DISTINCT ?_sameAs             ; separator=", " ) AS ?sameAs )     
        ( group_concat ( DISTINCT ?_paradigm_label     ; separator=", " ) AS ?paradigm )

WHERE
      { 
                      ?pl               rdf:type            dbo:ProgrammingLanguage ;
                                        rdfs:label          ?pl_label
                      FILTER ( LANG ( ?pl_label ) = 'en' ) .

          OPTIONAL  { ?pl               dbo:abstract        ?abstract . 
                      FILTER ( LANG ( ?abstract ) = 'en' ) . }

          OPTIONAL  { ?pl               dbo:influenced      ?_influenced . 
                      ?_influenced      rdfs:label          ?_influenced_label . 
                      FILTER ( LANG ( ?_influenced_label ) = 'en' ) . }

          OPTIONAL  { ?pl               dbo:influencedBy    ?_influencedBy . 
                      ?_influencedBy    rdfs:label          ?_influencedBy_label
                      FILTER ( LANG ( ?_influencedBy_label ) = 'en' ) . }

          OPTIONAL  { ?pl               owl:sameAs          ?_sameAs . } 

          OPTIONAL  { ?pl               dbp:paradigm        ?_paradigm .
                      ?_paradigm        rdfs:label          ?_paradigm_label 
                      FILTER ( LANG ( ?_paradigm_label ) = 'en' ) . }

          OPTIONAL { ?pl                dbo:thumbnail       ?_thumbnail . }

      } 

GROUP BY ?pl ?pl_label ?abstract ?_thumbnail

您还可以遵循以下网址:https://codepen.io/SergioBelevskij/pen/ZPdVyM

答案 2 :(得分:0)

在Polywhirl先生的回答的启发下,我创建了以下实现:

(为清楚起见,使用Typescript type annotations

type TypeInfo = { //the returned object format
    name: string;
    generics: TypeInfo[];
}

function parseGenerics(input: string): TypeInfo {
    input = input.trim();
    const startIndex = input.indexOf('<'),
          endIndex = input.lastIndexOf('>');

    if (startIndex !== -1 && endIndex === -1) {
        throw new Error("Missing closing bracket '>' for " + input);
    } else if (startIndex === -1 && endIndex !== -1) {
        throw new Error("Missing opening bracket '<' for " + input);
    } else if (startIndex === -1 && endIndex === -1) { //no generics
        return {
            name: input,
            generics: []
        };
    } else {
        const head = input.substring(0, startIndex),
              tail = input.substring(startIndex + 1, endIndex);

        return {
            name: head,
            generics: tail.split(/\s*,\s*/).map(parseGenerics)
        };
    }
}

使用Foo<Bar, Baz<Qux>>作为输入将导致:

{
    "name": "Foo",
    "generics": [
        {
            "name": "Bar",
            "generics": []
        },
        {
            "name": "Baz",
            "generics": [
                {
                    "name": "Qux",
                    "generics": []
                }
            ]
        }
    ]
}

与Polywhirl先生相比,我更喜欢这种实现方式,因为它可以立即创建正确的数据格式,而不需要其他转换步骤。 (我认为)这使它成为一种更清洁,更精简的解决方案。