当我想一个一个地替换最后一个匹配时,我遇到了问题expresión regular
,textarea
我解释说:
如果我在其中写入
@
,textarea
则会在选择时打开一个菜单,其中有用户名,它会使用所选名称自动完成。但是,如果我再次编写
@
并选择另一个用户,replace
它会在第一个@
.如果我写入
@a
并选择一个用户,然后我再次写入@a
并选择另一个用户,它会在最后一次匹配中正确替换。
我该如何解决第二点?
var arrobaGato = "";
var $textarea = $('textarea');
var $btndropdown = $('.dropdown button');
/*Detectamos @, # o espacio*/
$textarea.on('keypress', function (evt) {
if (evt.which == 64 || evt.which == 35) {
arrobaGato = String.fromCharCode(evt.which);
$btndropdown.dropdown('toggle');
} else if (evt.which == 32) {
arrobaGato = "";
$('.dropdown.open').removeClass('open');
}else if(arrobaGato != "" && !$('.dropdown').hasClass('open')){
$btndropdown.dropdown('toggle');
}
});
/*obtenemos el nombre seleccionado del menu*/
$('.dropdown li a').on('click', function(evt){
evt.preventDefault();
let txt = $textarea.val();
let usr = $(this).text();
let idusr = this.id;
switch(arrobaGato){
case "@":
regex1 = /[\@][\w\.\-_]*/g
matchs1 = txt.match(regex1);
//console.log(matchs1)
//console.log(matchs1[matchs1.length - 1])
//console.log(matchs1.length)
txt = txt.replace(matchs1[matchs1.length-1], "@" + usr + "~" + idusr + " ")
break;
case "#":
regex2 = /[\#][\w\.\-_]*/g
matchs2 = txt.match(regex2);
txt = txt.replace(matchs2[matchs2.length-1], "#" + usr + "~" + idusr + " ")
break;
}
match = [];
arrobaGato = "";
$textarea.val(txt);
});
textarea{
border: 1px solid gray;
height: 100px;
min-width: 100%;
max-width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<!--<div contenteditable="true"></div>-->
<br/><br/><br/>
<textarea autofocus="true"></textarea>
<div class="dropdown">
<button id="dLabel" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" style="display: none;">
Dropdown trigger
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li><a href="#" id='1'>User1</a></li>
<li><a href="#" id='2'>User2</a></li>
<li><a href="#" id='3'>User3</a></li>
<li><a href="#" id='4'>User4</a></li>
</ul>
</div>
问题
您遇到了一个非常常见的错误,即:
查找与搜索文本匹配的文本
替换在字符串中找到的文本
这将始终替换它匹配的文本的第一次出现,即使正则表达式匹配另一个位置的文本。
为了更容易解释,让我们看一个简化的例子:
第一次更正(回答问题)
为了使其始终匹配
@xx..
or的最后一次出现#yy...
,我们使用以下正则表达式?:^
-文本的开始(
..)
- Group 1 -保存从头到尾的文本[@#]
,因为它匹配:[\s\S]*
- 任意数量的字符。它与.*
(但与此不同的是,它也匹配\n
)。量词*
导致在要搜索的模式中最后出现的内容。[@#]
- 它是一个字符类,匹配 1 个字符(两者之一:符号或数字)。\S*
- 匹配所有非空白字符。或者,它可以用于仅替换它们不被空格分隔时
[^\s@#]*
的第一部分。@uno#dos
?
- 可选地在末尾添加一个空格(因为在替换中我们将添加 1 个空格)。也就是说,我们让正则表达式引擎消耗从文本开头到最后一个 的所有可能字符
[@#]
,并且我们正在记录该组 1 中匹配的文本,以便在替换为 时使用该匹配的反向引用$1
。例如,它匹配如下:所以在替换时它将
$1
包含@uno #dos tres @
.代码:
这就是替换
click
菜单事件中最后一次出现的全部内容:背景问题:在当前位置替换
解决方案真的要替换最后一次出现吗?如果用户移动了光标并在文本中间输入了怎么办?
获取当前位置之前的最后一次出现:
光标的位置是通过.selectionStart ( IE9+ )获得的。
如果有选定的文本,替换时我们从该位置删除到.selectionEnd。
我们将使用相同的正则表达式,用这些值进行修改。例如,如果光标位于位置10,我们将必须获取
[#@]
前 10 个字符中的最后一个字符,即最多9 个字符后跟 at 符号或数字:在代码中,使用RegExp()构造函数,将是:
更重要的是,现在我们可以使用这个策略来查看何时显示菜单以及何时隐藏它......
根据光标位置显示菜单:
首先,我们将文本放到光标位置:
[@#]
并且我们应该仅在到达该位置后有一个非空格字符时才显示菜单。也就是说,当它匹配时/[@#]\S*$/
(在末尾txtAntes
)。结束代码
我已经重构了你的代码,我想我已经解决了你的问题。
我所做的是首先检查
textarea
它是否为空,如果它是空的,只需插入选定的用户。如果它不为空,我首先将它传递到一个包含所有文本的变量中
textarea
,我对它进行清理@
并将其全部转换string
为 aarray
,我还将新选择的用户放入array
.然后它只剩下删除它
array
并使用前缀@
o将其转换#
并在textarea
.可以肯定地改进代码,例如,如果您选择了所有用户,
@
然后选择下一个用户,#
他们将全部更改为#
...但是正如我已经说过的,您在开始时遇到的问题已经消除。
很多废话……最好看代码: