Различия в поведении
Протестировано в Bash 4.3.11:
[
- POSIX [[
is расширение Bash [
- это просто регулярная команда со странным именем. ]
- это просто аргумент [
, который не позволяет использовать дополнительные аргументы. Ubuntu 16.04 фактически имеет исполняемый файл для него в /usr/bin/[
, предоставленный coreutils, но встроенная версия bash имеет приоритет. Ничто не изменяется в том, как Bash анализирует команду. В частности, <
является перенаправлением, &&
и ||
объединяют несколько команд, ( )
генерирует подоболочки, если не экранируется \
, и расширение слова происходит, как обычно. [[ X ]]
представляет собой единую конструкцию, которая делает X
разыгранным магическим образом. <
, &&
, ||
и ()
обрабатываются специально, а правила разделения слов различны. Существуют также дополнительные различия, такие как =
и =~
. В Bashese: [
- встроенная команда, а [[
- ключевое слово: https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and- shell-keyword <
[[ a < b ]]
: лексикографическое сравнение [ a \< b ]
: То же, что и выше. \
, или же перенаправление, как и для любой другой команды. Расширение Bash. Я не мог найти альтернативу POSIX, см. . Как проверить строки для меньших или равных? &&
и ||
[[ a = a && b = b ]]
: true, logical и [ a = a && b = b ]
: синтаксическая ошибка, &&
проанализирована как разделитель команды AND cmd1 && cmd2
[ a = a -a b = b ]
: эквивалентна, но устарела POSIX [ a = a ] && [ b = b ]
: рекомендация POSIX (
[[ (a = a || a = b) && a = b ]]
: false [ ( a = a ) ]
: синтаксическая ошибка, ()
интерпретируется как подоболочка [ \( a = a -o a = b \) -a a = b ]
: эквивалентна, но ()
устарела с помощью POSIX ([ a = a ] || [ a = b ]) && [ a = b ]
Рекомендация POSIX x='a b'; [[ $x = 'a b' ]]
: true, кавычки не нужны x='a b'; [ $x = 'a b' ]
: синтаксическая ошибка, расширяется до [ a b = 'a b' ]
x='a b'; [ "$x" = 'a b' ]
: эквивалентна =
[[ ab = a? ]]
: true, потому что она соответствует шаблону (* ? [
являются волшебными). Не расширяет glob для файлов в текущем каталоге. [ ab = a? ]
: a?
glob расширяется. Так может быть истинным или ложным в зависимости от файлов в текущем каталоге. [ ab = a\? ]
: false, а не расширение glob =
и ==
одинаковы для обоих [
и [[
, но ==
является расширением Bash. printf 'ab' | grep -Eq 'a.'
: эквивалент POSIX ERE [[ ab =~ 'ab?' ]]
: false, теряет магию с помощью ''
[[ ab? =~ 'ab?' ]]
: true =~
[[ ab =~ ab? ]]
: true, расширенное регулярное выражение POSIX match, ?
не glob expand [ a =~ a ]
: синтаксическая ошибка printf 'ab' | grep -Eq 'ab?'
: эквивалент POSIX Рекомендация
Я предпочитаю всегда использовать []
.
Есть эквиваленты POSIX для каждой конструкции [[ ]]
, которую я видел.
Если вы используете [[ ]]
, вы:
[
- это просто регулярная команда со странным именем, никакая специальная семантика не задействована. Вы переключаете String
, а subArea.StartsWith()
возвращает Boolean
, поэтому вы не можете этого сделать. Я предлагаю вам сделать это следующим образом:
if (subArea.StartsWith("3*") || subArea.StartsWith("03*"))
return "123";
switch(subArea)
{
case "4100":
case "4101":
case "4102":
case "4200":
return "ABC";
case "600A":
return "XWZ";
default:
return "ABCXYZ123";
}
Результат будет таким же.
С помощью LINQ, хороший ответ by @seriesOne можно немного упростить, заменив операторы foreach
и return
на:
// using System.Linq;
// Look for a match...
var result = cases
.Where(c => c.Item3(subArea, c.Item1))
.FirstOrDefault();
// Return the match or the default.
return result == null ? "ABCXYZ123" : result.Item2;
Просто для удовольствия, вот еще одно решение, которое позволяет избежать оператора switch.
var map = new[] {
new { Value = "4100", StartsWith = false, Result="ABC" },
new { Value = "4101", StartsWith = false, Result="ABC" },
new { Value = "4102", StartsWith = false, Result="ABC" },
new { Value = "4200", StartsWith = false, Result="ABC" },
new { Value = "600A", StartsWith = false, Result="XWZ" },
new { Value = "3*", StartsWith = true, Result="123" },
new { Value = "03*", StartsWith = true, Result="123" },
};
var subarea = ... whatever ...;
var result = map.Where(e =>
{
if (e.StartsWith)
{
return subarea.StartsWith(e.Value);
}
else
{
return subarea == e.Value;
}
}
)
.Select(e => e.Result)
.FirstOrDefault() ?? "ABCXZ123";
Порядок в массиве map
определяет приоритет, так что, например, вы можете иметь точное соответствие на, скажем, «3 * 11», а также совпадение StartsWith
на «3 *», например:
var map = new[] {
new { Value = "3*11", StartsWith = false, Result="ABC" },
new { Value = "4100", StartsWith = false, Result="ABC" },
new { Value = "4101", StartsWith = false, Result="ABC" },
new { Value = "4102", StartsWith = false, Result="ABC" },
new { Value = "4200", StartsWith = false, Result="ABC" },
new { Value = "600A", StartsWith = false, Result="XWZ" },
new { Value = "3*", StartsWith = true, Result="123" },
new { Value = "03*", StartsWith = true, Result="123" },
};
Ярлыки case должны быть строками, так как выражение switch является строкой; однако StartsWith
возвращает логическое значение. Я рекомендую обработать эти особые случаи в секции default
.
switch(subArea)
{
case "4100":
case "4101":
case "4102":
case "4200":
return "ABC";
case "600A":
return "XWZ";
default:
if (subArea.StartsWith("3") || subArea.StartsWith("03")) {
return "123";
}
return "ABCXYZ123";
}
Также звезда (*), вероятно, ошибается, если вы не хотите, чтобы subArea
содержал ее. StartWith
не принимает подстановочные знаки.
В качестве альтернативы вы можете использовать regex:
if (Regex.IsMatch(subArea, "^3|^03")) { // or "^(3|03)"
return "123";
}
, где ^
означает начало строки и |
означает или .
Джо меня избивает, но вот еще один способ, не связанный с переключением, который реализует алгоритм соответствия шаблону с набором правил.
private static string GetSomeStringOrOther(string subArea)
{
// Create a set of pattern matching functions...
Func<string, string, bool> matchEquals = (a, b) => a.Equals(b);
Func<string, string, bool> matchStarts = (a, b) => a.StartsWith(b);
// Create a rule set...
Tuple<string, string, Func<string, string, bool>>[] cases = new []
{
new Tuple<string, string, Func<string, string, bool>>("4100", "ABC", matchEquals),
new Tuple<string, string, Func<string, string, bool>>("4101", "ABC", matchEquals),
new Tuple<string, string, Func<string, string, bool>>("4102", "ABC", matchEquals),
new Tuple<string, string, Func<string, string, bool>>("4200", "ABC", matchEquals),
new Tuple<string, string, Func<string, string, bool>>("600A", "XWZ", matchEquals),
new Tuple<string, string, Func<string, string, bool>>("3*", "123", matchStarts),
new Tuple<string, string, Func<string, string, bool>>("03*", "123", matchStarts),
};
// Look for a match...
foreach(var matchCase in cases)
{
if(matchCase.Item3(subArea, matchCase.Item1))
{
// Return if it matches...
return matchCase.Item2;
}
}
// Otherwise return the default...
return "ABCXYZ123";
}
Преимущества
Недостатки
Усовершенствования
Tuple<string, string, Func<string, string, bool>>
семантическим объектом, который представляет Rule