Javascript:像这样准确地拆分字符串:/kick@Username";“原因”;但是用户名可以有特殊字符

Javascript:像这样准确地拆分字符串:/kick@Username";“原因”;但是用户名可以有特殊字符,javascript,regex,string,Javascript,Regex,String,这是我的困境 我希望能够拆分如下所示的字符串: /ban @User "because I told you so" 但是,使用空格、@或引号作为字符串分隔符的问题是,用户名可能包含大量特殊字符。而且,这些特殊字符可能会与处理命令发生冲突 例如: /ban @Person" "because why not" 不起作用,也不会 /ban @Person"name" "reason" 当我可以用来分割字符串的任何字符都可以很容易地被目标用户的名字模仿来破坏命令时,我如何才能准确地处理这样的事

这是我的困境

我希望能够拆分如下所示的字符串:

/ban @User "because I told you so"
但是,使用空格、@或引号作为字符串分隔符的问题是,用户名可能包含大量特殊字符。而且,这些特殊字符可能会与处理命令发生冲突

例如:

/ban @Person" "because why not"
不起作用,也不会

/ban @Person"name" "reason"
当我可以用来分割字符串的任何字符都可以很容易地被目标用户的名字模仿来破坏命令时,我如何才能准确地处理这样的事情?这有可能吗?老实说,RegExp对我来说有点让人望而生畏,所以如果这是一个简单的regex修复,我道歉:(

多亏了一个解决方案,我现在有了一个工作的处理器:

    var yourRegex = /^@(.*?) "([^"]+)"$/;
因为我已经可以去掉/ban(其他命令,比如/kick,等等,因为它不是唯一的一个命令),所以我只是从regexp中去掉了它。我还去掉了@符号,因为我不需要它来瞄准用户。100%工作:D

试试这个:

/^\/ban (@.*?) "([^"]+)"$/

这将为您提供第一个子模式中的用户名(带前导的
@
符号,如果要排除它,只需将其移到括号外),以及第二个子模式中的原因(如果不带引号,请将其移到括号内以包含它们).

正如我在评论中提到的,我通过使用最小的解析器来完成类似的任务。下面是CoffeeScript中的一个解析器,它编译为JavaScript:

parse = (input) ->
  index = 0
  peek = -> input.charAt index
  advance = -> ++index; peek()
  advanceRP = ->
    last = peek()
    advance()
    return last
  collect = (regex) -> (advanceRP() while peek().match regex).join ''
  skipWhiteSpace = -> collect /\s/
  literal = ->
    result = collect /[@\w]/
    skipWhiteSpace()
    return result
  string = ->
    if peek() == '"'
      advance()
      result = []
      loop
        result.push collect /[^"]/
        advance()  # skip past closing quote
        if peek() is '"'  # and therefore an escape (double quote)
          result.push '"'
        else if peek().match /\s?/
          break  # whitespace or end of input; end of string
        else
          # neither another quote nor whitespace;
          # they probably forgot to escape the quote.
          # be lenient, here.
          result.push '"'
      skipWhiteSpace()
      result.join ''
    else
      literal()

  return error: 'does not start with slash' if peek() isnt '/'
  advance()
  command = literal()
  return error: 'command unrecognized' if command isnt 'ban'
  person = string()
  if peek() == '"'
    reason = string()
    return error: 'junk after end of command' if index < input.length
  else
    reason = input.substring index

  command: 'ban'
  person: person
  reason: reason

我必须这样做。我的解决方案是构建一个小解析器,因此对于“简单”名称,您可以将名称放在那里,但是对于任何更复杂的名称,您可以引用它,如果它包含引号,则可以转义引号。稍微复杂一点,但它工作得很好。我认为
*?
也可以用
*这里。嘿,我测试了这个,它工作得很好。再次感谢——现在我有了获取@Usernames的基础,我可以将它调整为其他命令,例如/swap@Username@OtherUsername。当它允许我时,我会接受你的答案:P另外,请注意,我添加了空格,因为StackOverflow认为我试图通知人们哈哈。@pimvdb,那会有什么变化?谢谢
coffee> parse '/ban @person reason'
{ command: 'ban', person: '@person', reason: 'reason' }
coffee> parse '/ban "@person with ""escaped"" quotes" and the reason doesn\'t need "quotes"'
{ command: 'ban'
, person: '@person with "escaped" quotes'
, reason: 'and the reason doesn\'t even need "quotes"'
}