仅使用文本偏移在字符串中插入标记

时间:2012-09-20 22:21:40

标签: javascript jquery regex text offset

我一直在努力使用javascript字符串方法和正则表达式,我可能会忽略一些显而易见的事情。我希望通过更详细地重述tofutim的question来违反任何协议。对他的问题的回答集中在s.replace()上,但为了使其起作用,你必须知道要替换的子串的出现,替换所有子串,或者能够以某种方式识别要替换的字符串。正则表达式。和他一样,我有一系列文本偏移,如下所示:

[[5,9], [23,27]]

和这样的字符串:

"eggs eggs spam and ham spam"

考虑到这些限制,是否有一种简单的方法(javaScript或jQuery的快捷方式)来获得这样的字符串?

"eggs <span>eggs</span> spam and ham <span>spam</span>"

我事先并不知道替换字符串是什么,或者基本文本中可能出现的字符串数量。我只知道它们的偏移量,并且由我们想要用标签包装的偏移所识别的事件。

有什么想法吗?

5 个答案:

答案 0 :(得分:3)

我找到了一种用regexp做的方法。不确定性能,但它简短而且甜美:

/**
 * replaceOffset
 * @param str A string
 * @param offs Array of offsets in ascending order [[2,4],[6,8]]
 * @param tag HTML tag
 */
function replaceOffset(str, offs, tag) {
  tag = tag || 'span';
  offs.reverse().forEach(function(v) {
    str = str.replace(
      new RegExp('(.{'+v[0]+'})(.{'+(v[1]-v[0])+'})'), 
      '$1<'+tag+'>$2</'+tag+'>'
    );
  });
  return str;
}

演示: http://jsbin.com/aqowum/3/edit

答案 1 :(得分:1)

您可以尝试slice方法。

var arr = [[5,9], [23,27]];
arr = arr.reverse()

$.each(arr, function(i, v){
    var f = v[0], last = v[1];
    $('p').html(function(i, v){
        var o = v.slice(0, f);
        var a = '<span>' + v.slice(f, last) + '</span>';
        var c = v.slice(last, -1);
        return o+a+c
    })
})

http://jsfiddle.net/rjQt7/

答案 2 :(得分:1)

iquick解决方案(未经测试)

function indexWrap(indexArr,str){
  // explode into array of each character
  var chars = str.split('');
  // loop through the MD array of indexes
  for(var i=0; i<indexArr.length;i++){
    var indexes = indexArr[i];
    // if the two indexes exist in the character array
    if(chars[indexes[0]] && chars[indexes[1]]){
      // add the tag into each index
      chars.splice(indexes[0],0,"<span>");
      chars.splice(indexes[1],0,"</span>");
    }
  }
  // return the joined string
  return chars.join('');  
}

就个人而言,我喜欢字符串替换解决方案,但如果你不想要一个,这可能会起作用

答案 3 :(得分:1)

首先,你想要向后迭代,以确保你最终不会覆盖之前所做的替换,但是,在我的例子中它并不重要,因为字符串在最后一次被重新组装

// > interpolateOnIndices([[5,9], [23,27]], "eggs eggs spam and ham spam");
// < 'eggs <span>eggs</span> spam and ham <span>spam</span>'

function interpolateOnIndices(indices, string) {
    "use strict";
    var i, pair, position = string.length,
        len = indices.length - 1, buffer = [];
    for (i = len; i >= 0; i -= 1) {
        pair = indices[i];
        buffer.unshift("<span>",
                       string.substring(pair[0], pair[1]),
                       "</span>",
                       string.substring(pair[1], position));
        position = pair[0];
    }
    buffer.unshift(string.substr(0, position));
    return buffer.join("");
}

这比使用splice的示例稍好一些,因为它不会创建额外的数组(splice本身会创建其他数组)。在其他函数中重复使用映射和创建函数是一定的内存耗尽,但它运行得不是很快......虽然它有点短。

理论上,在大型字符串连接时,应该优先于多个连接,因为内存分配将进行一次,而不是随后丢弃一个半生不熟的字符串。当然,除非您正在处理大量数据,否则所有这些都不需要关注您。


修改

因为我手上有太多时间,所以我决定进行一项测试,看看变量将如何在更大(但相当实际)的数据集上进行比较,下面是我的测试代码,其中包含一些结果... < / p>

function interpolateOnIndices(indices, string) {
    "use strict";
    var i, pair, position = string.length,
        len = indices.length - 1, buffer = [];
    for (i = len; i >= 0; i -= 1) {
        pair = indices[i];
        buffer.unshift("<span>",
                       string.substring(pair[0], pair[1]),
                       "</span>",
                       string.substring(pair[1], position));
        position = pair[0];
    }
    buffer.unshift(string.substr(0, position));
    return buffer.join("");
}

function indexWrap(indexArr, str) {
    var chars = str.split("");
    for(var i = 0; i < indexArr.length; i++) {
        var indexes = indexArr[i];
        if(chars[indexes[0]] && chars[indexes[1]]){
            chars.splice(indexes[0], 0, "<span>");
            chars.splice(indexes[1], 0, "</span>");
        }
    }
    return chars.join("");
}

function replaceOffset(str, offs, tag) {
    tag = tag || "span";
    offs.reverse().forEach(
        function(v) {
            str = str.replace(
                new RegExp("(.{" + v[0] + "})(.{" + (v[1] - v[0]) + "})"), 
                "$1<" + tag + ">$2</" + tag + ">"
            );
        });
    return str;
}

function generateLongString(pattern, times) {
    "use strict";
    var buffer = new Array(times);
    while (times >= 0) {
        buffer[times] = pattern;
        times -= 1;
    }
    return buffer.join("");
}

function generateIndices(pattern, times, step) {
    "use strict";
    var buffer = pattern.concat(), block = pattern.concat();
    while (times >= 0) {
        block = block.concat();
        block[0] += step;
        block[1] += step;
        buffer = buffer.concat(block);
        times -= 1;
    }
    return buffer;
}

var longString = generateLongString("eggs eggs spam and ham spam", 100);
var indices = generateIndices([[5,9], [23,27]], 100,
                              "eggs eggs spam and ham spam".length);

function speedTest(thunk, times) {
    "use strict";
    var start = new Date();
    while (times >= 0) {
        thunk();
        times -= 1;
    }
    return new Date() - start;
}

speedTest(
    function() {
        replaceOffset(longString, indices, "span"); },
    100); // 1926

speedTest(
    function() {
        indexWrap(indices, longString); },
    100); // 559

speedTest(
    function() {
        interpolateOnIndices(indices, longString); },
    100); // 16

在amd64 Linux(FC-17)上针对V8(Node.js)进行了测试。

我没有测试undefined的答案,因为我不想加载那个库,特别是因为它没有对这个测试做任何有用的事情。我想它会在两个人之间以及elclanrs的变体之间徘徊,更多的是对elclanrs的回答。

答案 4 :(得分:0)

您可以使用子字符串方法 String.substring(startIndex,endIndex); description:在start&amp;之间返回字符串。结束指数 用法:

var source="hello world";
var result=source.substring (3,7); //returns 'lo wo'

你已经有了一个带有初始&amp;的数组。最终索引,所以你差不多完成了:)