gpt4 book ai didi

javascript - 替换后正确的子串位置

转载 作者:行者123 更新时间:2023-12-03 03:16:25 26 4
gpt4 key购买 nike

我有一个由用户提供的这样的函数:

function replace_function(string) {
return string.replace(/:smile:/g, '⻇')
.replace(/(foo|bar|baz)/g, 'text_$1');
}

我有这样的输入字符串:

var input = 'foo bar :smile: xxxx';

我有一个从 0 到输入字符串长度的数字,我用它来执行子字符串来分割字符串。

我需要找到替换后与输出字符串匹配的数字(位置),以便分割位于相同的视觉位置。分割只是为了可视化,我只需要数字。

输出字符串可以具有相同的长度,这只适用于输入和输出长度不同的情况(例如提供函数和输入字符串的宽度)

function replace_function(string) {
return string.replace(/:smile:/g, '⻇')
.replace(/(foo|bar|baz)/g, 'text_$1');
}

var textarea = document.querySelector('textarea');
var pre = document.querySelector('pre');
function split() {
var input = textarea.value;
var output = replace_function(input);
// find position for output
var position = textarea.selectionStart;
var split = [
output.substring(0, position),
output.substring(position)
];
pre.innerHTML = JSON.stringify(split);
}
textarea.addEventListener('click', split);
<textarea>xxx foo xxx bar xxx :smile: xxxx</textarea>
<pre></pre>

当您单击要替换的单词的中间时,位置/分割需要位于输出单词之后。如果您在单词之前、之间或之后单击,则位置需要位于同一位置(每种情况下的位置都会不同,以匹配正确的位置)

更新:这是我的代码,仅适用于 :smile: 输入,但在 :smile: 之前需要有文本(输入 = ":smile: asdas"且位置位于中间微笑并且位置已关闭)

它适用于被 text_foo 替换的 foo,但不适用于 foo 之前有 :smile: 的情况(输入“asd :smile: asd foo”)。

var get_position = (function() {
function common_string(formatted, normal) {
function longer(str) {
return found && length(str) > length(found) || !found;
}
var formatted_len = length(formatted);
var normal_len = length(normal);
var found;
for (var i = normal_len; i > 0; i--) {
var test_normal = normal.substring(0, i);
var formatted_normal = replace_function(test_normal);
for (var j = formatted_len; j > 0; j--) {
var test_formatted = formatted.substring(0, j);
if (test_formatted === formatted_normal &&
longer(test_normal)) {
found = test_normal;
}
}
}
return found || '';
}
function index_after_formatting(position, command) {
var start = position === 0 ? 0 : position - 1;
var command_len = length(command);
for (var i = start; i < command_len; ++i) {
var substr = command.substring(0, i);
var next_substr = command.substring(0, i + 1);
var formatted_substr = replace_function(substr);
var formatted_next = replace_function(next_substr);
var substr_len = length(formatted_substr);
var next_len = length(formatted_next);
var test_diff = Math.abs(next_len - substr_len);
if (test_diff > 1) {
console.log('return ' + i);
return i;
}
}
}
return function get_formatted_position(position, command) {
var formatted_position = position;
var string = replace_function(command);
var len = length(string);
var command_len = length(command);
if (len !== command_len) {
var orig_sub = command.substring(0, position);
var orig_len = length(orig_sub);
var sub = replace_function(orig_sub);
var sub_len = length(sub);
var diff = Math.abs(orig_len - sub_len);
if (false && orig_len > sub_len) {
formatted_position -= diff;
} else if (false && orig_len < sub_len) {
formatted_position += diff;
} else {
var index = index_after_formatting(position, command);
var to_end = command.substring(0, index + 1);
//formatted_position -= length(to_end) - orig_len;
formatted_position -= orig_len - sub_len;
if (orig_sub && orig_sub !== to_end) {
var formatted_to_end = replace_function(to_end);
var common = common_string(formatted_to_end, orig_sub);
var re = new RegExp('^' + common);
var before_end = orig_sub.replace(re, '');
var to_end_rest = to_end.replace(re, '');
var to_end_rest_len = length(replace_function(to_end_rest));
if (before_end && orig_sub !== before_end) {
var commnon_len = length(replace_function(common));
formatted_position = position - length(before_end) + to_end_rest_len;
}
}
}
if (formatted_position > len) {
formatted_position = len;
} else if (formatted_position < 0) {
formatted_position = 0;
}
}
return formatted_position;
};
})();

function length(str) {
return str.length;
}

function replace_function(string) {
return string.replace(/:smile:/g, '⻇')
.replace(/(foo|bar|baz)/g, 'text_$1');
}

var textarea = document.querySelector('textarea');
var pre = document.querySelector('pre');
function split() {
var input = textarea.value;
var output = replace_function(input);
// find position for output
var position = get_position(textarea.selectionStart, input);
var split = [
output.substring(0, position),
output.substring(position)
];
pre.innerHTML = JSON.stringify(split);
}
textarea.addEventListener('click', split);
<textarea>xxxx :smile: xxxx :smile: xxx :smile:</textarea>
<pre></pre>

最佳答案

为此,您必须使用 RegExp#exec 循环自行执行 replace 操作,并跟踪替换如何影响位置等沿着这些思路(但这可能可以优化):

function trackingReplace(rex, string, replacement, position) {
var newString = "";
var match;
var index = 0;
var repString;
var newPosition = position;
var start;
rex.lastIndex = 0; // Just to be sure
while (match = rex.exec(string)) {
// Add any of the original string we just skipped
if (rex.global) {
start = rex.lastIndex - match[0].length;
} else {
start = match.index;
rex.lastIndex = start + match[0].length;
}
if (index < start) {
newString += string.substring(index, start);
}
index = rex.lastIndex;
// Build the replacement string. This just handles $$ and $n,
// you may want to add handling for $`, $', and $&.
repString = replacement.replace(/\$(\$|\d)/g, function(m, c0) {
if (c0 == "$") return "$";
return match[c0];
});
// Add on the replacement
newString += repString;
// If the position is affected...
if (start < position) {
// ... update it:
if (rex.lastIndex < position) {
// It's after the replacement, move it
newPosition = Math.max(0, newPosition + repString.length - match[0].length);
} else {
// It's *in* the replacement, put it just after
newPosition += repString.length - (position - start);
}
}

// If the regular expression doesn't have the g flag, break here so
// we do just one replacement (and so we don't have an endless loop!)
if (!rex.global) {
break;
}
}
// Add on any trailing text in the string
if (index < string.length) {
newString += string.substring(index);
}
// Return the string and the updated position
return [newString, newPosition];
}

这是一个片段,显示我们使用不同的位置进行测试:

function trackingReplace(rex, string, replacement, position) {
var newString = "";
var match;
var index = 0;
var repString;
var newPosition = position;
var start;
rex.lastIndex = 0; // Just to be sure
while (match = rex.exec(string)) {
// Add any of the original string we just skipped
if (rex.global) {
start = rex.lastIndex - match[0].length;
} else {
start = match.index;
rex.lastIndex = start + match[0].length;
}
if (index < start) {
newString += string.substring(index, start);
}
index = rex.lastIndex;
// Build the replacement string. This just handles $$ and $n,
// you may want to add handling for $`, $', and $&.
repString = replacement.replace(/\$(\$|\d)/g, function(m, c0) {
if (c0 == "$") return "$";
return match[c0];
});
// Add on the replacement
newString += repString;
// If the position is affected...
if (start < position) {
// ... update it:
if (rex.lastIndex < position) {
// It's after the replacement, move it
newPosition = Math.max(0, newPosition + repString.length - match[0].length);
} else {
// It's *in* the replacement, put it just after
newPosition += repString.length - (position - start);
}
}

// If the regular expression doesn't have the g flag, break here so
// we do just one replacement (and so we don't have an endless loop!)
if (!rex.global) {
break;
}
}
// Add on any trailing text in the string
if (index < string.length) {
newString += string.substring(index);
}
// Return the string and the updated position
return [newString, newPosition];
}

function show(str, pos) {
console.log(str.substring(0, pos) + "|" + str.substring(pos));
}
function test(rex, str, replacement, pos) {
show(str, pos);
var result = trackingReplace(rex, str, replacement, pos);
show(result[0], result[1]);
}
for (var n = 3; n < 22; ++n) {
if (n > 3) {
console.log("----");
}
test(/([f])([o])o/g, "test foo result foo x", "...$2...", n);
}
.as-console-wrapper {
max-height: 100% !important;
}

这是您更新后的代码片段以使用它:

function trackingReplace(rex, string, replacement, position) {
var newString = "";
var match;
var index = 0;
var repString;
var newPosition = position;
var start;
rex.lastIndex = 0; // Just to be sure
while (match = rex.exec(string)) {
// Add any of the original string we just skipped
if (rex.global) {
start = rex.lastIndex - match[0].length;
} else {
start = match.index;
rex.lastIndex = start + match[0].length;
}
if (index < start) {
newString += string.substring(index, start);
}
index = rex.lastIndex;
// Build the replacement string. This just handles $$ and $n,
// you may want to add handling for $`, $', and $&.
repString = replacement.replace(/\$(\$|\d)/g, function(m, c0) {
if (c0 == "$") return "$";
return match[c0];
});
// Add on the replacement
newString += repString;
// If the position is affected...
if (start < position) {
// ... update it:
if (rex.lastIndex < position) {
// It's after the replacement, move it
newPosition = Math.max(0, newPosition + repString.length - match[0].length);
} else {
// It's *in* the replacement, put it just after
newPosition += repString.length - (position - start);
}
}

// If the regular expression doesn't have the g flag, break here so
// we do just one replacement (and so we don't have an endless loop!)
if (!rex.global) {
break;
}
}
// Add on any trailing text in the string
if (index < string.length) {
newString += string.substring(index);
}
// Return the string and the updated position
return [newString, newPosition];
}

function replace_function(string, position) {
var result = trackingReplace(/:smile:/g, string, '⻇', position);
result = trackingReplace(/(foo|bar|baz)/g, result[0], 'text_$1', result[1]);
return result;
}

var textarea = document.querySelector('textarea');
var pre = document.querySelector('pre');
function split() {
var position = textarea.selectionStart;
var result = replace_function(textarea.value, position);
var string = result[0];
position = result[1];
var split = [
string.substring(0, position),
string.substring(position)
];
pre.innerHTML = JSON.stringify(split);
}
textarea.addEventListener('click', split);
<textarea>:smile: foo</textarea>
<pre></pre>

关于javascript - 替换后正确的子串位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46754022/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com