将引号中的字符串作为单个命令参数捕获 [英] Capture strings in quotes as single command argument

查看:43
本文介绍了将引号中的字符串作为单个命令参数捕获的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试制作一个Discord机器人,该机器人与服务器进行一些交互.

我已经写了一些可以工作的代码,但是这有很大的问题.这是我的代码:

  if(命令===文件"){var accusor = message.author.id;var username = args [0];var reason = args [1];var惩罚= args [2];var duration = args [3];if(!duration)duration ="N/A";console.log(返回最后的" +金额+为" +用户名);request.post({url:'http://grumpycrouton.com/kismet/api/post_complaint.php',格式:{accusor:accusor,search:username,reason:reason,punishment:punishment,duration:duration}},function(err,httpResponse,body){message.reply(body);});} 

命令是!file {playername} {reason} {punishment} {duration} ,但是问题是有时某些变量可能包含多个单词.例如, {reason} 可能类似于播放器的时光不好",但是由于参数的分割方式,我的代码无法正确解析此内容.

让我们输入以下命令:

!file GrumpyCrouton玩家的时光不好"踢"1天" 但是参数实际上会以不同的方式散布,因为第三个参数中有空格,但是正则表达式将所有参数都用空格分隔,而不考虑引号.基本上,Discord会忽略引号,并使用每个单词作为自己的参数,从而使 {punishment} {duration} 的参数索引分别为6和7,而不是2和3,因为每个单词都被当作一个参数.

这是我的论据的读取方式:

  const args = message.content.slice(config.prefix.length).trim().split(/+/g);const命令= args.shift().toLowerCase(); 

如何使引号中的字符串作为单个参数而不是多个参数读取?

解决方案

我遇到了这个问题,因为我对OP的要求与之相似(解析一个字符串,该字符串可能包含带双引号的参数并带有嵌入式空格).但是,被接受的答案并不能满足我的需要(它会删除空格,并过多地考虑了参数的数量).因此,我不得不设计自己的解决方案,以防其他人发现它有用.

实际上有两种变体:第一种是 not 不允许双引号出现在生成的参数列表中;第二种是 not .第二个确实通过在双引号字符串中使用双引号( ..." ... )来实现此目的.(我实际上首先写了这个版本,因为这是Windows下Node处理事情的方式",然后将其缩减为第一个变体.

在两个示例中, log()函数,以及从 splitCommandLine()内部调用它的函数,纯粹是为了显示内部工作原理,可以省略./p>


简单的双引号字符串

  • 参数通常会在空格处分割.
  • 双引号字符串即使包含空格也被视为一个参数.
  • 内的多个空格将被保留.
  • 多个空格用双引号引起来,它们将被视为一个空格.
  • 如果缺少最后一个双引号,则会假定为该
  • .
  • 不可能在参数中添加双引号字符.

  splitCommandLine('param1"param 2" param3"param 4""param 5');log('argv',process.argv.slice(2));函数log(n,v){console.log(n);console.dir(v);console.log();}函数splitCommandLine(commandLine){log('commandLine',commandLine);//找到空格字符的唯一标记.//以'< SP>'开头并在必要时重复添加"@"以使其唯一.var spaceMarker ='< SP>';while(commandLine.indexOf(spaceMarker)> -1)spaceMarker + ='@';//保护双引号字符串.//o查找用双引号引起来的非双引号字符串.//o最后的双引号是可选的,以允许使用不终止的字符串.//o将每个双引号字符串替换为qouble引号内的内容,//将每个空格字符替换为上面的空格标记后.//o外部的双引号将不存在.var noSpacesInQuotes = commandLine.replace(/([[^"] *)?/g,(fullMatch,capture)=> {返回capture.replace(//g,spaceMarker);});log('noSpacesInQuotes',noSpacesInQuotes);//既然这样做是安全的,请在一个或多个空格处分割命令行.var mangledParamArray = noSpacesInQuotes.split(/+/);log('mangledParamArray',mangledParamArray);//通过从任何空间标记还原空间来创建新数组.var paramArray = mangledParamArray.map((mangledParam)=> {返回mangledParam.replace(RegExp(spaceMarker,'g'),'');});log('paramArray',paramArray);返回paramArray;} 

使用与代码中嵌入的命令行相同的命令行运行此命令,表明它产生与Node/Windows命令行解析器相同的输出:

  C:\>节点test1.js param1"param 2" param3"param 4""param 5命令行'param1"param 2" param3"param 4""param 5"noSpacesInQuotes'param1< SP< SP> SP< SP> SP< SP> SP< SP> 2 param3 param< SP< SP> SP< 4> SP< SP>参数< SP> 5'mangledParamArray['param1','< SP> SP< SP>参数< SP> SP< SP> 2','param3','param< SP> SP< 4> SP< SP>','param< SP> 5']paramArray['param1','param2','param3','param 4','param 5']精氨酸['param1','param2','param3','param 4','param 5'] 


带双引号的双引号字符串

  • 与第一个示例完全相同,除了,在双引号字符串中是双双引号( ..."aaa""bbb""ccc"... )将在解析参数( aaa"bbb" ccc )中插入双引号.在双引号字符串之外,双引号双引号将被忽略.这模仿了Windows下的Node如何解析命令行(未经Unix版本测试).

  splitCommandLine('param1"param 2" param" 3"param""4""param 5');log('argv',process.argv.slice(2));函数log(n,v){console.log(n);console.dir(v);console.log();}函数splitCommandLine(commandLine){log('commandLine',commandLine);//查找成对的双引号字符的唯一标记.//以'< DDQ>'开头并在必要时重复添加"@"以使其唯一.var doubleDoubleQuote ='< DDQ>';while(commandLine.indexOf(doubleDoubleQuote)> -1)doubleDoubleQuote + ='@';//用上面的标记替换所有双引号对.var noDoubleDoubleQuotes = commandLine.replace(/"/g,doubleDoubleQuote);log('noDoubleDoubleQuotes',noDoubleDoubleQuotes);//如上所述,找到一个唯一的空格标记.var spaceMarker ='< SP>';while(commandLine.indexOf(spaceMarker)> -1)spaceMarker + ='@';//保护双引号字符串.//o查找用双引号引起来的非双引号字符串.//o最后的双引号是可选的,以允许使用不终止的字符串.//o将每个双引号字符串替换为qouble引号内的内容,//将每个空格字符替换为上面的空格标记后;//,并且每个双引号标记都已替换为双引号,//引用字符.//o外部的双引号将不存在.var noSpacesInQuotes = noDoubleDoubleQuotes.replace(/([^"] *)?/g,(fullMatch,capture)=> {返回capture.replace(//g,spaceMarker).replace(RegExp(doubleDoubleQuote,'g'),''));});log('noSpacesInQuotes',noSpacesInQuotes);//既然这样做是安全的,请在一个或多个空格处分割命令行.var mangledParamArray = noSpacesInQuotes.split(/+/);log('mangledParamArray',mangledParamArray);//通过从任何空间标记还原空间来创建新数组.还有,任何//其余的双引号标记必须在OUTSIDE外部//带引号的字符串,因此将被删除.var paramArray = mangledParamArray.map((mangledParam)=> {返回mangledParam.replace(RegExp(spaceMarker,'g'),'').replace(RegExp(doubleDoubleQuote,'g'),'');});log('paramArray',paramArray);返回paramArray;} 

同样,此代码以与Node/Windows相同的方式解析命令字符串:

  C:\>节点test2.js param1"param 2" param" 3"param""4""param 5命令行'param1"param 2" param" 3"param""4""param 5'noDoubleDoubleQuotes'param1"param 2" param< DDQ> 3"param< DDQ> 4""param 5"noSpacesInQuotes'param1< SP> SP< SP> SP< SP> SP< SP> 2 param< DDQ> 3 param< SP"< SP> SP< 4> SP< SP> SP< SP>; SP> 5'mangledParamArray['param1','< SP> SP< SP>参数< SP> SP< SP> 2',"param< DDQ> 3","param< SP>"< SP> SP< SP>",'param< SP> 5']paramArray['param1','param2','param3','param"4','param 5']精氨酸['param1','param2','param3','param"4','param 5'] 

I'm attempting to make a Discord bot that does some interactions with a server.

I've written some code that sort of works, but there is a big problem with it. Here is my code:

if (command === "file") {

        var accusor = message.author.id;
        var username = args[0];
        var reason = args[1];
        var punishment = args[2];
        var duration = args[3];
        if(!duration) duration = "N/A";
        console.log("Returning last " + amount + " for " + username);
        request.post({url:'http://grumpycrouton.com/kismet/api/post_complaint.php', form: {accusor:accusor,search:username,reason:reason,punishment:punishment,duration:duration}}, function(err,httpResponse,body) { 
            message.reply(body); 
        });
    }

The command is !file {playername} {reason} {punishment} {duration}, but the problem is, sometimes a few of the variables may have multiple words. For example, {reason} could be something like "Player had a bad time" but my code is unable to parse this correctly because of the way the arguments are split up.

Let's say this command is entered:

!file GrumpyCrouton "Player had a bad time" Kick "1 Day" But the arguments would actually be spread out differently, because the 3rd argument has spaces in it but the regex splits all of the argument by spaces regardless of quotes. Basically Discord ignores the quotes and uses each word as it's own argument, thus making the {punishment} and {duration} have an argument index that is 6 and 7 instead of 2 and 3, because every word is counted as an argument.

This is the way my arguments are read:

const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
const command = args.shift().toLowerCase();

How can I make it so strings enclosed in quotes are read as a single argument instead of multiple?

解决方案

I got to this question because I has a similar requirement to the OP (parsing a string that may contain double-quoted parameters with embedded spaces). However, the accepted answer did not do what I needed (it strips spaces, and assumes too much about the number of parameters). I therefore had to devise my own solution which I offer here in case anyone else finds it useful.

There are actually two variants: the first does not allow double-quotes to appear in the generated parameter list; the second does allow this by using a double-double-quote (...""...) within a double-quoted string. (I actually wrote this version first "because that's how Node under Windows does things" and then cut it down for the first variant.

In both examples, the log() function, and calls to it from within splitCommandLine(), are purely to show the inner workings and can be omitted.


Simple Double-Quoted Strings

  • Parameters will normally be split on spaces.
  • Double-quoted strings are treated as one parameter even if they contain spaces.
  • Multiple spaces within double-quotes will be preserved.
  • Multiple spaces outside double-quotes they will be treated as a single space.
  • If a final, closing double-quote is missing, it will be assumed.
  • It is not possible to get a double-quote character into a parameter.

splitCommandLine( 'param1   "   param   2" param3 "param  4  " "param 5' ) ;

log( 'argv', process.argv.slice(2) ) ;

function log( n, v ) {
    console.log( n ) ;
    console.dir( v ) ;
    console.log() ;
}

function splitCommandLine( commandLine ) {

    log( 'commandLine', commandLine ) ;

    //  Find a unique marker for the space character.
    //  Start with '<SP>' and repeatedly append '@' if necessary to make it unique.
    var spaceMarker = '<SP>' ;
    while( commandLine.indexOf( spaceMarker ) > -1 ) spaceMarker += '@' ;

    //  Protect double-quoted strings.
    //   o  Find strings of non-double-quotes, wrapped in double-quotes.
    //   o  The final double-quote is optional to allow for an unterminated string.
    //   o  Replace each double-quoted-string with what's inside the qouble-quotes,
    //      after each space character has been replaced with the space-marker above.
    //   o  The outer double-quotes will not be present.
    var noSpacesInQuotes = commandLine.replace( /"([^"]*)"?/g, ( fullMatch, capture ) => {
        return capture.replace( / /g, spaceMarker ) ;
    }) ;

    log( 'noSpacesInQuotes', noSpacesInQuotes ) ;

    //  Now that it is safe to do so, split the command-line at one-or-more spaces.
    var mangledParamArray = noSpacesInQuotes.split( / +/ ) ;

    log( 'mangledParamArray', mangledParamArray ) ;

    //  Create a new array by restoring spaces from any space-markers.
    var paramArray = mangledParamArray.map( ( mangledParam ) => {
        return mangledParam.replace( RegExp( spaceMarker, 'g' ), ' ' ) ;
    });

    log( 'paramArray', paramArray ) ;

    return paramArray ;
}

Running this, with the same command-line as embedded in the code shows that it produces the same output as the Node/Windows command-line parser:

C:\>node test1.js param1   "   param   2" param3 "param  4  " "param 5
commandLine
'param1   "   param   2" param3 "param  4  " "param 5'

noSpacesInQuotes
'param1   <SP><SP><SP>param<SP><SP><SP>2 param3 param<SP><SP>4<SP><SP> param<SP>5'

mangledParamArray
[ 'param1',
  '<SP><SP><SP>param<SP><SP><SP>2',
  'param3',
  'param<SP><SP>4<SP><SP>',
  'param<SP>5' ]

paramArray
[ 'param1', '   param   2', 'param3', 'param  4  ', 'param 5' ]

argv
[ 'param1', '   param   2', 'param3', 'param  4  ', 'param 5' ]


Double-Quoted Strings with Double-Double-Quotes

  • Exactly the same as the first example, except that within a double-quoted string, a double-double-quote (..."aaa ""bbb"" ccc"...) will insert a double-quote in the parsed-parameter (aaa "bbb" ccc). Outside of a double-quoted string, a double-double-quote will be ignored. This mimics how Node under Windows parses the command-line (not tested on Unix-variants).

splitCommandLine( 'param1   "   param   2" param""3 "param "" 4  " "param 5' ) ;

log( 'argv', process.argv.slice(2) ) ;

function log( n, v ) {
    console.log( n ) ;
    console.dir( v ) ;
    console.log() ;
}

function splitCommandLine( commandLine ) {

    log( 'commandLine', commandLine ) ;

    //  Find a unique marker for pairs of double-quote characters.
    //  Start with '<DDQ>' and repeatedly append '@' if necessary to make it unique.
    var doubleDoubleQuote = '<DDQ>' ;
    while( commandLine.indexOf( doubleDoubleQuote ) > -1 ) doubleDoubleQuote += '@' ;

    //  Replace all pairs of double-quotes with above marker.
    var noDoubleDoubleQuotes = commandLine.replace( /""/g, doubleDoubleQuote ) ;

    log( 'noDoubleDoubleQuotes', noDoubleDoubleQuotes ) ;

    //  As above, find a unique marker for spaces.
    var spaceMarker = '<SP>' ;
    while( commandLine.indexOf( spaceMarker ) > -1 ) spaceMarker += '@' ;

    //  Protect double-quoted strings.
    //   o  Find strings of non-double-quotes, wrapped in double-quotes.
    //   o  The final double-quote is optional to allow for an unterminated string.
    //   o  Replace each double-quoted-string with what's inside the qouble-quotes,
    //      after each space character has been replaced with the space-marker above;
    //      and each double-double-quote marker has been replaced with a double-
    //      quote character.
    //   o  The outer double-quotes will not be present.
    var noSpacesInQuotes = noDoubleDoubleQuotes.replace( /"([^"]*)"?/g, ( fullMatch, capture ) => {
        return capture.replace( / /g, spaceMarker )
                      .replace( RegExp( doubleDoubleQuote, 'g' ), '"' ) ;
    }) ;

    log( 'noSpacesInQuotes', noSpacesInQuotes ) ;

    //  Now that it is safe to do so, split the command-line at one-or-more spaces.
    var mangledParamArray = noSpacesInQuotes.split( / +/ ) ;

    log( 'mangledParamArray', mangledParamArray ) ;

    //  Create a new array by restoring spaces from any space-markers. Also, any
    //  remaining double-double-quote markers must have been from OUTSIDE a double-
    //  quoted string and so are removed.
    var paramArray = mangledParamArray.map( ( mangledParam ) => {
        return mangledParam.replace( RegExp( spaceMarker,       'g' ), ' ' )
                           .replace( RegExp( doubleDoubleQuote, 'g' ), ''  ) ;
    });

    log( 'paramArray', paramArray ) ;

    return paramArray ;
}

Again, this code parses a command-string in the same way as Node/Windows:

C:\>node test2.js param1   "   param   2" param""3 "param "" 4  " "param 5
commandLine
'param1   "   param   2" param""3 "param "" 4  " "param 5'

noDoubleDoubleQuotes
'param1   "   param   2" param<DDQ>3 "param <DDQ> 4  " "param 5'

noSpacesInQuotes
'param1   <SP><SP><SP>param<SP><SP><SP>2 param<DDQ>3 param<SP>"<SP>4<SP><SP> param<SP>5'

mangledParamArray
[ 'param1',
  '<SP><SP><SP>param<SP><SP><SP>2',
  'param<DDQ>3',
  'param<SP>"<SP>4<SP><SP>',
  'param<SP>5' ]

paramArray
[ 'param1', '   param   2', 'param3', 'param " 4  ', 'param 5' ]

argv
[ 'param1', '   param   2', 'param3', 'param " 4  ', 'param 5' ]

这篇关于将引号中的字符串作为单个命令参数捕获的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆