如何在正则表达式中删除字符串末尾的重复字符

3

有人能帮我解决以下正则表达式吗?

<script type="text/javascript">
        function quoteWords() {
            var search = document.getElementById("search_box");
            search.value = search.value.replace(/^\s*|\s*$/g, ""); //trim string of ending and beginning whitespace
            if(search.value.indexOf(" ") != -1){ //if more then one word
                search.value = search.value.replace(/^"*|"*$/g, "\"");
            }
        }
  </script>

<input type="text" name="keywords" value="" id="search_box" size="17">
<input onClick="quoteWords()" type="submit" value="Go">
问题:手动添加双引号并提交时会出现错误,会在末尾添加一个额外的双引号。正则表达式应该查看双引号是否存在,不应该添加任何内容。

所以它将"long enough"变成了"long enough"" <- 在末尾添加了一个额外的双引号。

有人可以检查一下正则表达式代码,看如何解决这个问题。

我只希望双引号被插入一次。


你是想要在值有多个单词且尚未被引号包裹时,将其用双引号“包装”起来吗? - Jake Dempsey
1
我被难住了,据我所知 * 总是贪心地行事,所以它应该能够工作。 - Jonathon
我相信你应该在第一个输入元素中使用id="search_box" - Matty K
@Matty K,这是旧代码中的一个类型错误。这两个ID是相同的。 - Ibn Saeed
@Jonathon - 我也是,这是一个有趣的边缘情况。 - Justin Morgan
显示剩余2条评论
4个回答

3
错误肯定发生在这一行:
search.value = search.value.replace(/^"*|"*$/g, "\"");

由于“*匹配0个或多个引号”,因此需要注意。然而,您可能不希望仅使用“+”来替换它,因为这不能实现您想要的将带有空格的字符串加上双引号的目的。
您可能只想用两个语句执行以下操作:
search.value = search.value.replace(/^"*|"*$/g, '')
search.value = '"' + search.value + '"'

重要的一点是没有“字符串结束”字符需要消耗 - 正则表达式引擎“知道”何时到达字符串末尾。因此,在匹配字符串末尾的引号后,光标会直接移动到字符串末尾,并在离开字符串之前再次找到空字符串。因此,字符串末尾的引号被替换为引号,字符串末尾的“nothing”也被替换为引号。
我建议您自己查看ECMAScript规范http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf 15.5.4.10和15.5.4.11节。但是,我还在this gist提供了一个直观的说明。
编辑:由于人们似乎对为什么会发生这种情况感到困惑,这里有些东西可能会有所帮助:

http://www.grymoire.com/Unix/Sed.html#uh-6

这是来自sed文档的说明,但它解释了为什么将*和/g结合使用是不好的想法。JS并不会在您这样做时发生异常,这是其优点之一。请注意,在字符串的每个位置都有无限数量的“0字符”。


1
我直觉地怀疑正则表达式替换算法由于替换 $ 的方式而出现了错误。如果你从没有引号的状态开始,然后不断点击按钮,你最终会得到一个引号,然后是两个引号,但永远不会再多了。也许全局 $ 搜索在正则表达式引擎中有一个残留的第二匹配,导致了第二次“替换”。 - Matty K
1
@Jonathon 基本上,由于它在全局替换“0个或多个引号后跟输入结束”,它发现了两次-一次是引号,另一次是引号和输入结束之间的空白。我的代码只是去掉引号(如果存在),然后像 OP 想要的那样添加一个漂亮的配对。预计到达时间:关键是 /g。 - Tamzin Blake
1
我非常确定问题不在于零或多个引号的全局匹配,因为JavaScript显然可以在字符串开头优雅地处理它。对我来说,问题似乎在于第一个匹配没有“消耗”掉字符串结尾标记。我无法理解为什么会进行两次替换。 - Matty K
但我仍然认为这不应该那么困难,特别是在这种情况下,它匹配了 $,因此字符串的结尾字符应该被消耗掉,程序应该退出而不是找到另一个匹配。 - Jonathon
更新了。现在这个工作方式很有道理。也许未来一个好的启发是“永远不要在字符串的末尾全局匹配0个或更多个字符”。 - Tamzin Blake
显示剩余14条评论

3
我猜想你的问题是在像“long enough”这样的字符串上得到了三个匹配。第一个匹配是开头加上第一个引号(因为正则表达式默认是贪婪的)。第二次匹配是结束引号和结束字符串($). 然而,由于字符串结尾不是实际字符,可能会出现第三个零字符的匹配。
一种可能的解决方案是在字符串中添加引号,然后用一个或多个引号替换零个或多个引号。
search.value = (search.value + '"').replace(/^"*|"+$/g, "\"");

你的解决方案可行。我会继续测试,看是否出现任何问题。 - Ibn Saeed

2
在正则表达式中,*匹配前面项的0个或多个实例,+ 匹配前面项的1个或多个实例。由于您使用了*,因此第一个正则表达式匹配到的是0个或更多与\s匹配的字符,第二个正则表达式匹配到的是0个或更多的"。将*改为+应该可以给您带来期望的结果。
编辑:如果您想使结果被双引号包围(如果它们不存在于行的开头或结尾),请使用类似于/ ^ [^"] | [^"] $ / 的内容,该内容读作“一行的开头后跟任何非双引号字符或任何非双引号字符后跟该行的结尾”。
双重编辑:这可能应该是/ ^ [^"\ w] | [^"\ w] $ / ,以确保您不替换匹配的第一个和最后一个字符 :/

我认为他想确保双引号存在,仅在双引号不存在时添加它们。 - jswolf19
@Jonathon Wisnoski,我在另一个问题中回复了。但我认为您没有得到StackOverFlow的通知。 - Ibn Saeed
如果您输入文本 a b,那么使用 + 不会添加引号来生成 "a b"。我相信让 OP 困惑的原因 - 并且随后也让我困惑了 - 是为什么在代码保持不变的情况下,输入 a b 并点击两次按钮最终得到的字符串是 "a b" 然后是 "a b"" - Matty K
@jswolf19,我认为你是对的,我更新了我的答案以反映这一点。@MattyK - 因为它用双引号替换任意数量的双引号,然后跟随着一行的结尾,我认为,但我不确定,因为我只是在脑海中解释这个问题,第一个单引号在那里是因为第一个引号被剥离和替换(如果是这种情况,只需输入“example lample”应该会导致“xample lample”... - jdd
@jeremiahd,/^[^"\w]|[^"\w]$/ 在字符串的开头和结尾都添加了双引号。因此,这个正则表达式并不能解决这个问题。 - Ibn Saeed
显示剩余5条评论

1

你可以使用+代替*

search.value = search.value.replace(/^"+|"+$/g, '"');

+符号不符合我的要求。我需要双引号自动插入。 - Ibn Saeed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接