Ответ 1
Вы показали свой код - это хорошо, но кажется, что вы не подумали о том, разумно ли вы разбирать такую команду:
- Во-первых, ваш код позволит использовать новый символ строки внутри имени и параметров команды. Было бы разумным, если бы вы предполагали, что новый символ линии никогда не будет там.
- Во-вторых,
\
также должен быть экранирован как"
, так как не будет никакого способа указать один\
в конце параметра, не вызывая путаницы. - В-третьих, немного странно, что имя команды обрабатывается так же, как параметры - имена команд обычно определяются и фиксируются, поэтому нет необходимости разрешать гибкие способы его указания.
Я не могу придумать однострочное решение в JavaScript, которое является общим. JavaScript regex не хватает \G
, который утверждает последнюю границу соответствия. Поэтому мое решение должно будет поступить с началом строкового утверждения ^
и прерывания строки в соответствии с токеном.
(Здесь не так много кода, в основном комментарии)
function parseCommand(str) {
/*
* Trim() in C# will trim off all whitespace characters
* \s in JavaScript regex also match any whitespace character
* However, the set of characters considered as whitespace might not be
* equivalent
* But you can be sure that \r, \n, \t, space (ASCII 32) are included.
*
* However, allowing all those whitespace characters in the command
* is questionable.
*/
str = str.replace(/^\s*\//, "");
/* Look-ahead (?!") is needed to prevent matching of quoted parameter with
* missing closing quote
* The look-ahead comes from the fact that your code does not backtrack
* while the regex engine will backtrack. Possessive qualifier can prevent
* backtracking, but it is not supported by JavaScript RegExp.
*
* We emulate the effect of \G by using ^ and repeatedly chomping off
* the string.
*
* The regex will match 2 cases:
* (?!")([^ ]+)
* This will match non-quoted tokens, which are not allowed to
* contain spaces
* The token is captured into capturing group 1
*
* "((?:[^\\"]|\\[\\"])*)"
* This will match quoted tokens, which consists of 0 or more:
* non-quote-or-backslash [^\\"] OR escaped quote \"
* OR escaped backslash \\
* The text inside the quote is captured into capturing group 2
*/
var regex = /^ *(?:(?!")([^ ]+)|"((?:[^\\"]|\\[\\"])*)")/;
var tokens = [];
var arr;
while ((arr = str.match(regex)) !== null) {
if (arr[1] !== void 0) {
// Non-space token
tokens.push(arr[1]);
} else {
// Quoted token, needs extra processing to
// convert escaped character back
tokens.push(arr[2].replace(/\\([\\"])/g, '$1'));
}
// Remove the matched text
str = str.substring(arr[0].length);
}
// Test that the leftover consists of only space characters
if (/^ *$/.test(str)) {
return tokens;
} else {
// The only way to reach here is opened quoted token
// Your code returns the tokens successfully parsed
// but I think it is better to show an error here.
return null;
}
}