如何从字符串中删除特殊字符集,但保留第一个字符?

4

我希望能够移除字符串中存在的特殊字符,除了第一个。

下面是我的代码,如果特殊字符不相邻,则可以正常工作:

特殊字符集 = '❶❷❸❹❺❻❼❽❾❿➀'

我的当前代码如下:

let str = '❶Hi dear how❽ are❺ ❽you❼';
const len = str.length;
for(let i = 0; i < len; i++){
  if(i !== 0){
    if(str[i] === '❶' || str[i] === '❷' || str[i] === '❸' ||
    str[i] === '❹' || str[i] === '❺' || str[i] === '❻' || str[i] === '❼' ||
    str[i] === '❽' || str[i] === '❾' || str[i] === '❿' || str[i] === '➀'){
      str = str.replace(str[i], '');
    }
  }
}

console.log('output: ', str);

上述代码运行良好,但如果我像下面这样改变字符串,它就无法工作:

let str = '❶Hi dear how❽ are❺❼ ❽❽you❼';

期望输出:

❶Hi dear how are you

如果使用正则表达式可以比我的解决方案更快,那么最好能够用正则表达式解决这个问题。


在我的问题中,我只打算保留一个特殊字符集,如果它仅存在于索引0中。 - Muhammad
4个回答

3

https://jsben.ch/Hcjqp

忽略第一个字符,直接进行替换。在此之上进行基准测试。

const replace = str => str[0] + str.slice(1).replace(/[❶-➀]+/g, '');
let str = '❶Hi dear how❽ are❺ ❽you❼'.repeat(2000);
console.log(replace(str));


所有三个答案在 Chrome 上都对我有用,我正在使用 react-native 并且只想选择最快的方法。我会为这些答案投票,但我必须选择最快和最稳定的方法作为解决方案。 - Muhammad
1
如果您只需要检查第一个字符,那么单独检查第一个字符并在直接替换中忽略第一个字符会更快。否则,回溯将是最快的,但在Safari上不起作用。除非您要进行数十万次替换,否则性能差异不应该明显。 - user120242
1
现在看来,即使对于非第一个字符,从第一次出现的位置进行分片,然后直接替换仍然会更快。 - user120242
1
不应该有任何区别。这是同一件事。 - user120242
1
我给你点赞,我喜欢这里的关注点分离。使用星号否定回顾来覆盖第一个字符的替换既不利于性能,也不利于清晰度。 - raina77ow
显示剩余10条评论

2

以下的正则表达式在Firefox和Safari中不能工作...

正则表达式: ([❶❷❸❹❺❻❼❽❾❿➀])(?<!^[❶❷❸❹❺❻❼❽❾❿➀])

它将替换除第一个之外的所有特殊字符...

代码:

str = "❶Hi dear how❽ are❺❼ ❽❽you❼'"

console.log(str.replace(/([❶❷❸❹❺❻❼❽❾❿➀])(?<!^[❶❷❸❹❺❻❼❽❾❿➀])/gm,''))


1
"(?<!^)" 应该已经足够了。但是在 Firefox 和 Safari 中这不起作用(因为那里还不支持后顾)。 - raina77ow
1
谢谢你让我测试,你的答案看起来是更简洁的方式,请希望这样可以更快地完成工作。 - Muhammad
好的答案。考虑放弃捕获组,并为更好的可读性将回顾放在匹配之前。 - Cary Swoveland

2
错误很微妙:当你从字符串中删除一个字符时,你应该同时减少索引,像这样:

str = str.replace(str[i--], '');

当你删除字符但将光标留在原地并在下一步前移时,这就是为什么你的原始代码无法删除重复的“黑名单”字符。

是的,使用正则表达式替换很容易实现:

const blacklistCharacterClass = /[❶❷❸❹❺❻❼❽❾❿➀]/g;
const rawString = '❶Hi dear how❽ are❺❼ ❽❽you❼';
const refinedString = rawString.replace(blacklistCharacterClass, (c, i) => i ? '' : c);
console.log(refinedString); // ❶Hi dear how are you

非常感谢您的解决方案,它非常有效。我已经为您的答案点赞了。如果您能够使用“正则表达式”解决它,那就更好了,因为当前的解决方案在长字符串(例如10k个字符)中有点慢。 - Muhammad
1
@Muhammad 添加了正则表达式选项。 - raina77ow
非常感谢,我现在正在测试所有答案,我必须选择一个能够执行“更快”的工作。 - Muhammad
你能猜出哪个更快,你的第一种解决方案还是第二种? - Muhammad
1
你可以用 jsperf 或 jsbench 来测试性能。你是否真的遇到了性能问题? - user120242

2
我假设特殊字符不一定在行首。
你可以将以下正则表达式的匹配项转换为空字符串。
(?<=[❶❷❸❹❺❻❼❽❾❿➀].*)[❶❷❸❹❺❻❼❽❾❿➀]

演示

这个正则表达式的意思是,“匹配一个感兴趣的字符,该字符之前有一个感兴趣的字符”(因为这些字符将被替换为空字符串)。

请注意,正向后查找不能锚定到行的开头。


自从写了上面的内容后,我已经了解到我误解了问题(请参见下面的评论)。但是我还是会留下来。

当已知字符串的第一个字符是特殊字符时,一种进行替换的方法是使用正则表达式的每个匹配项

(?<=.)[❶❷❸❹❺❻❼❽❾❿➀]

用空字符串替换;也就是说,用空字符串替换每个特殊字符,该字符之前有另一个字符(因此不是字符串中的第一个字符)。


非常感谢,您的答案让我感觉它运行得更快,而且更简洁,因为我需要接受答案以加速。但是在这个答案中,有一件事情不符合我的期望,请参见我的问题,我只说了第一个字符,我的意思是如果它是特殊字符之一,则索引0应该保留。 - Muhammad
现在我只想给你的答案点个赞。 - Muhammad
1
如果您坚持,我认为@GolamMazid Sajib的正则表达式解决方案是不错的(尽管我认为他的正则表达式中的捕获组是不必要的)。最好不要编辑您的问题以澄清“第一个字符”,因为这会使我的答案不正确。但是,您可以在问题下添加一条评论,说明您打算将“第一个字符”解释为字符串中的第一个字符。 - Cary Swoveland
谢谢,好的,我会在我的问题下面添加一个注释来澄清它。 - Muhammad
说实话,我真的认为采用@user120242的方法更容易实现性能和清晰度。确实,正则表达式引擎应该优化这个问题,但它是实现特定的。顺便说一下,这个问题不能简化为(?<!^)吗? - raina77ow

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