3

我一直在努力使用 javascript 字符串方法和正则表达式,我可能忽略了一些明显的东西。我希望通过更详细地重申 tofutim 的问题,我没有违反任何协议。对他的问题的回答集中在 s.replace() 上,但要让它起作用,您必须知道要替换哪个子字符串,替换所有子字符串,或者能够以某种方式唯一地识别要替换的字符串正则表达式。像他一样,我只有一个这样的文本偏移数组:

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

和这样的字符串:

"eggs eggs spam and ham spam"

鉴于这些限制,是否有一种直接的方法(javaScript 或 jQuery 的一些快捷方式)来获得这样的字符串?

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

我事先不知道替换字符串是什么,或者在基本文本中可能出现了多少次。我只知道它们的偏移量,而且我只想用标签包装它们的偏移量所标识的事件。

有什么想法吗?

4

5 回答 5

4

我找到了一种使用正则表达式的方法。不确定性能,但它简短而甜蜜:

/**
 * 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

于 2012-09-20T23:26:16.637 回答
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("");
}

这比带有spliceing 的示例要好一些,因为它不会创建额外的数组(拼接本身会创建额外的数组)。在其他函数中重复使用映射和创建函数会占用一定的内存,但它的运行速度也不是很快......虽然它有点短。

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


编辑:

因为我手头有太多时间,所以我决定做一个测试,看看如何在更大(但相当现实)的数据集上比较变化,下面是我的测试代码和一些结果......

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) 进行了测试。

我没有测试未定义的答案,因为我不想加载那个库,尤其是它对这个测试没有任何用处。我想它会在 andbeyond's 和 elclanrs 的变体之间借用某个地方,尽管更倾向于 elclanrs 的答案。

于 2012-09-20T23:18:39.553 回答
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/

于 2012-09-20T22:38:53.117 回答
1

快速解决方案(未测试)

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('');  
}

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

于 2012-09-20T22:41:10.193 回答
0

您可以使用子字符串方法 String.substring (startIndex, endIndex); 描述:返回开始和结束索引之间的字符串使用:

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

你已经有一个带有初始和最终索引的数组,所以你几乎完成了:)

于 2012-09-20T22:39:59.680 回答