将动态类型分配给字符串

时间:2019-03-05 11:29:52

标签: javascript typescript

基于下面的data,我需要按其offsetlength值细分文本。

const data = {
  "text": "Do you have questions or comments and do you wish to contact ABC? Please visit our customer support page.",
  "inlineEntityRanges": [{
    "type": "LINK",
    "offset": 83,
    "length": 16,
    "data": {
      "target": "_self",
      "url": "/index.htm"
    }
  }]
}

使用以下代码段,我可以在任意特定位置细分文本。

那是什么问题?

我想按以下格式细分文本,并为其分配动态类型。

如何分配类型?

如果响应中未提及任何类型,则其默认类型应为text。如果响应中存在类型值,则应分配相应的值。

所以最终的期望输出应该是这样的,

  [{
    data: 'Do you have questions or comments and do you wish to contact ABC? Please visit our',
    type: 'text'
  },
  {
    data: 'customer support',
    type: 'link'
  },
  {
    data: 'page.',
    type: 'text'
  }]

请帮助。

let inlineEntity = [];
const data = {
  "text": "Do you have questions or comments and do you wish to contact ABC? Please visit our customer support page.",
  "inlineStyleRanges": [{
    "style": "BOLD",
    "offset": 12,
    "length": 20,
    "type": "style"
  }],
  "inlineEntityRanges": [{
    "type": "LINK",
    "offset": 83,
    "length": 16,
    "data": {
      "target": "_self",
      "url": "/index.htm"
    }
  }]
}
const intoPairs = xs => xs.slice(1).map((x, i) => [xs[i], x])
const breakAt = (places, str) => intoPairs([0, ...places, str.length]).map(
  ([a, b]) => str.substring(a, b)
)
const breakWhere = (words, str) => breakAt(
  words.slice(0).sort(({
    offset: o1
  }, {
    offset: o2
  }) => o1 - o2).reduce(
    (a, {
      offset,
      length
    }) => [...a, offset, offset + length], []
  ),
  str
)

const str = data.text;
const inlineRanges = data.inlineEntityRanges

inlineRanges.forEach(range => {
  console.log(breakWhere([{
    offset: range.offset,
    length: range.length
  }], str));
})

2 个答案:

答案 0 :(得分:0)

尝试以下解决方案:

let inlineEntity = [];
const data = {
    "text": "Do you have questions or comments and do you wish to contact ABC? Please visit our customer support page.",
    "inlineStyleRanges": [{
        "style": "BOLD",
        "offset": 12,
        "length": 20,
        "type": "style"
    }],
    "inlineEntityRanges": [{
        "type": "LINK",
        "offset": 83,
        "length": 16,
        "data": {
            "target": "_self",
            "url": "/index.htm"
        }
    }]
}

const MARKER = '||||';

function breakByRanges(ranges, text, tempString) {
    const result = [];
    ranges.forEach((styleRange) => {
        const { offset, length, type } = styleRange;
        const str = text.slice(offset, offset + length + 1);
        tempString = tempString.replace(str, MARKER);
        result.push({ data: str, type });
    })

    return { result, tempString };
}

function breakData(data, ranges) {
    const { inlineStyleRanges, inlineEntityRanges, text } = data;
    const result = [];
    let tempText = text;
    let { result: styleResult, tempString: styleTempText } = breakByRanges(inlineStyleRanges, text, tempText);
    tempText = styleTempText;
    result.push(...styleResult);


    let { result: entityResult, tempString: entityTempText } = breakByRanges(inlineEntityRanges, text, styleTempText);
    tempText = entityTempText;
    result.push(...entityResult);

    let orderNumber = 0;
    const textItems = tempText.split(MARKER).map((data, index) => {
        if (result[index]) {
            result[index].order = orderNumber + index + 1;
        }
        const resultData = { data, type: 'text', order: orderNumber + index };
        orderNumber += 1;
        return resultData;
    });
    result.push(...textItems);
    return result.sort((first, second) => first.order - second.order).map((item) => ({ data: item.data, type: item.type }));
}
console.log(JSON.stringify(breakData(data)))

答案 1 :(得分:0)

另一种可能性是my answer对上一个问题的改编,将辅助函数合并到主要函数中并更新为新的组合输入格式是:

const breakData = (data) => {
  const nodes = (data.inlineStyleRanges || [])
    .concat(data.inlineEntityRanges || [])
    .sort(({offset: o1}, {offset: o2}) => o1 - o2)
  const str = data.text || ''
  const indices = [
    0, 
    ...nodes.reduce((a, {offset, length}) => [...a, offset, offset + length], []),
    str.length
  ]

  const slim = ({offset, length, data, ...rest}) => ({...rest, ...data})

  return indices.slice(1).map((x, i) => [indices[i], x])
    .map(([a, b]) => str.substring(a, b))
    .map((s, i) => i % 2 == 0 
      ? {data: s, type: 'text'}     
      : {data: s, ...slim(nodes[(i - 1) / 2])}
    ).filter(({data}) => data.length > 0)
}

const data = {"text": "Do you have questions or comments and do you wish to contact ABC? Please visit our customer support page.", "inlineEntityRanges": [{"data": {"target": "_self", "url": "/index.htm"}, "length": 16, "offset": 83, "type": "LINK"}], "inlineStyleRanges": [{"length": 21, "offset": 12, "style": "BOLD", "type": "style"}]}

console.log(breakData(data))

每个节点返回的数据比您的请求多,包括styleurltarget节点。 (这有一个奇怪的地方:我将urltarget节点提升了一个层次,因为它们的父节点是data与输出中的data冲突;我如果您对输出节点中的text而不是data感到满意,则可以在三元数中替换它,并将其用于slim:{ {1}})

如果您不希望这种扩展行为,可以通过替换来更改

({offset, length ...rest}) => ({...rest})

与此:

      : {data: s, ...slim(nodes[(i - 1) / 2])}

(此时您也可以删除 : {data: s, type: nodes[(i - 1) / 2].type} 。)

这可能就是您想要做的,但是我写的版本保留了所有可能对下游有用的信息。


(一件愚蠢的事情:“文本” /“样式” /“ LINK”的大写字母差异确实困扰着我不知道的我的某些OCD部分。看在天上,将其更改为“链接”。;- )