我试图制作与服务器进行某些互动的Discord机器人。
我已经编写了一些有用的代码,但它存在很大问题。这是我的代码:
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);
});
}
命令是!file {playername} {reason} {punishment} {duration}
,但问题是,有时一些变量可能有多个单词。例如,{reason}
可能类似于"播放器的时间不好"但是由于参数被拆分的方式,我的代码无法正确解析它。
让我们说输入这个命令:
!file GrumpyCrouton "Player had a bad time" Kick "1 Day"
但是参数实际上会以不同的方式展开,因为第三个参数中有空格,但正则表达式将所有参数按空格分割,而不管引号如何。基本上,Discord忽略引号并使用每个单词作为它自己的参数,从而使{punishment}
和{duration}
的参数索引为6和7而不是2和3,因为每个单词都是被算作参数。
这是我的论据阅读方式:
const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
const command = args.shift().toLowerCase();
我怎样才能这样做,所以用引号括起来的字符串被读作一个参数而不是多个?
答案 0 :(得分:1)
您可以找到引号的所有索引,并使用该信息通过将输入传递给input.substring来正确分割输入。这样的事情应该有效:
const input = '!file GrumpyCrouton \"Player had a bad time\" Kick \"1 Day\"';
var raw = input;
raw = raw.split(' ');
let command = raw.splice(0, 1)[0]; // splice out the command (splice returns an array)
let user = raw.splice(0, 1)[0]; // splice out the user
let recompose = raw.join(''); // recompose the string WITHOUT any spaces
let indices = []; // find the indices of the quotation marks
for (var i in recompose) {
let char = recompose[i];
if (char === '"') {
indices.push(i);
}
}
console.log(indices, recompose);
if (indices.length == 4) { // OK!
// use the indices to break up input string into substrings
let reason = recompose.substring(indices[0] + 1, indices[1]);
let punishment = recompose.substring(indices[1], indices[2]).replace('"', '');
let duration = recompose.substring(indices[2], indices[3]).replace('"', '');
console.log(command);
console.log(user);
console.log(reason);
console.log(punishment);
console.log(duration);
} else {
// bad input!
}
您可以尝试在jsfiddle上试用此代码!
答案 1 :(得分:1)
我遇到了这个问题,因为我对OP有类似的要求(解析一个可能包含带双引号的参数且带有嵌入式空格的字符串)。但是,被接受的答案并不能满足我的需要(它会删除空格,并过多地考虑了参数的数量)。因此,我不得不设计自己的解决方案,以防其他人发现它有用。
实际上有两种变体:第一种是 not 不允许双引号出现在生成的参数列表中;第二个确实通过在双引号字符串内使用双双引号(...""...
)来实现此目的。 (我实际上首先写了这个版本,“因为这是Windows下Node处理事情的方式”,然后将其缩减为第一个变体。
在两个示例中,log()
函数以及从splitCommandLine()
内部对其的调用,纯粹是为了显示内部工作原理,可以省略。
简单的双引号字符串
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 ;
}
使用与代码中嵌入的命令行相同的命令行运行此命令,表明它产生与Node / Windows命令行解析器相同的输出:
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' ]
带双引号的双引号字符串
..."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) ) ;
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 ;
}
同样,此代码以与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' ]
答案 2 :(得分:0)
您可以添加更明确的分隔符,例如&#34; |&#34;并使用拆分(&#39; |&#39;)
您的输入将是:!file GrumpyCrouton | &#34;球员的时间不好&#34; |踢| &#34; 1天&#34;
答案 3 :(得分:0)
一个简单的正则表达式就可以解决问题:)
const input = 'ban user "Look at what you have done!" 7d "This is another string" value';
const regex = new RegExp('"[^"]+"|[\\S]+', 'g');
const arguments = [];
input.match(regex).forEach(element => {
if (!element) return;
return arguments.push(element.replace(/"/g, ''));
});
console.log(arguments);
/*
* Use a function with a spreader like:
* doSomething(...arguments);
*/