2015-05-18 3 views
32

Я хотел был бы сопоставить строки с подстановочным знаком (*), где подстановочный знак означает «любой». Например:Соответствующие строки с подстановочным знаком

*X = string must end with X 
X* = string must start with X 
*X* = string must contain X 

Кроме того, некоторые соединения использует такие как:

*X*YZ* = string contains X and contains YZ 
X*YZ*P = string starts with X, contains YZ and ends with P. 

Существует простой алгоритм, чтобы сделать это? Я не уверен в использовании регулярного выражения (хотя это и есть возможность).

Чтобы уточнить, пользователи будут вводить вышеуказанное в поле фильтра (как можно более простой фильтр), я не хочу, чтобы им приходилось самостоятельно писать регулярные выражения. Так что я могу легко трансформироваться из вышеупомянутых обозначений.

+0

Должен 'YZ ABC x' матч' X * YZ * ', то есть сделать подстроки должны появляться в том же порядке, как в строке и шаблон или нет? Я бы предположил, что это не должно совпадать, но «строка содержит X и содержит YZ» не дает понять. Если он должен совпадать, все текущие ответы неверны. – Dukeling

+0

Это было бы. В приведенном примере X должен появиться перед YZ. – Robinson

ответ

17

Просто FYI, вы могли использовать VB.NET Like-Operator:

string text = "x is not the same as X and yz not the same as YZ"; 
bool contains = LikeOperator.LikeString(text,"*X*YZ*", Microsoft.VisualBasic.CompareMethod.Binary); 

Используйте CompareMethod.Text, если вы хотите игнорировать ю e случай.

Необходимо добавить using Microsoft.VisualBasic.CompilerServices;.

+0

hmm, добавив «используя» результаты в: 'Тип или имя пространства имен 'CompilerServices' не существует в пространстве имен 'Microsoft.VisualBasic' (вам не хватает ссылки на сборку?' –

+3

Вам нужно добавить ссылку на Microsoft.VisualBasic. dll: https://stackoverflow.com/a/21212268/284240 –

4

*X*YZ* = string contains X and contains YZ

@".*X.*YZ" 

X*YZ*P = string starts with X, contains YZ and ends with P.

@"^X.*YZ.*P$" 
+0

ОК, так что с регулярным выражением нет ничего, что я могу просто заменить *, чтобы получить то, что хочу? Эти запросы будут выполняться пользователями, и я не ожидаю, что они поймут регулярные выражения. – Robinson

+0

Да, но начинать и заканчивать нужно, чтобы указать якоря. '^' start, '$' end –

+0

OK спасибо Avinash. Это просто заменит * на. * Для регулярного выражения. – Robinson

4

Подстановочный знак * может быть переведен как .* или .*? regex pattern.

Возможно, вам понадобится использовать режим одиночной линии для соответствия символам новой строки, и в этом случае вы можете использовать (?s) как часть шаблона регулярных выражений.

Вы можете установить его в целом или в части шаблона:

X* = > @"X(?s:.*)" 
*X = > @"(?s:.*)X" 
*X* = > @"(?s).*X.*" 
*X*YZ* = > @"(?s).*X.*YZ.*" 
X*YZ*P = > @"(?s:X.*YZ.*P)" 
+0

Они не эквивалентны в каждом случае. Например, подстановочный знак Windows '* .htm' также будет соответствовать' * .html'. –

60

Часто, дикие карты работают с два типа шутников:

? - any character (one and only one) 
    * - any characters (zero or more) 

так что вы можете легко конвертировать эти правила в соответствующие регулярный экспресс-экспресс n:

// If you want to implement both "*" and "?" 
    private static String WildCardToRegular(String value) { 
    return "^" + Regex.Escape(value).Replace("\\?", ".").Replace("\\*", ".*") + "$"; 
    } 

    // If you want to implement "*" only 
    private static String WildCardToRegular(String value) { 
    return "^" + Regex.Escape(value).Replace("\\*", ".*") + "$"; 
    } 

И тогда вы можете использовать Regex как обычно:

String test = "Some Data X"; 

    Boolean endsWithEx = Regex.IsMatch(test, WildCardToRegular("*X")); 
    Boolean startsWithS = Regex.IsMatch(test, WildCardToRegular("S*")); 
    Boolean containsD = Regex.IsMatch(test, WildCardToRegular("*D*")); 

    // Starts with S, ends with X, contains "me" and "a" (in that order) 
    Boolean complex = Regex.IsMatch(test, WildCardToRegular("S*me*a*X")); 
+1

Отличное решение! –

+0

Это не так просто, как вы утверждаете. Например, одна специальность заключается в том, что при использовании 'Directory.GetFiles' расширение в три буквы' .htm' также будет соответствовать '.html', но расширение с двумя буквами' .ai' не будет match 'aix' или' aifg'. Подстановочные знаки Windows тривиальны с первого взгляда, но под капотом они представляют собой набор устаревших наборов правил гиперкомплексов. –

+1

@Sebastian Mach: Спасибо, что упомянул нюанс! Я согласен с тем, что MS DOS (и Windows) inte rpretation * wild cards * отличается от стандартного https://en.wikipedia.org/wiki/Wildcard_character. Однако вопрос о строках и не упоминает файлы; поэтому я поставил простейшее решение, предполагая, что '*' есть любые символы (ноль или более) и '?', являющиеся ровно одним символом. –

10

Использование WildcardPattern из System.Management.Automation может быть вариантом.

pattern = new WildcardPattern(patternString); 
pattern.IsMatch(stringToMatch); 

Visual Studio UI не может позволить вам добавить System.Management.Automation сборки в ссылки вашего проекта. Не стесняйтесь добавлять его вручную, как описано here.

2

Необходимо учитывать, что Regex IsMatch дает true с XYZ при проверке соответствия с Y *.Чтобы избежать этого, я использую "^" якорь

isMatch(str1, "^" + str2.Replace("*", ".*?")); 

Таким образом, полный код, чтобы решить ваши проблемы

bool isMatchStr(string str1, string str2) 
    { 
     string s1 = str1.Replace("*", ".*?"); 
     string s2 = str2.Replace("*", ".*?"); 
     bool r1 = Regex.IsMatch(s1, "^" + s2); 
     bool r2 = Regex.IsMatch(s2, "^" + s1); 
     return r1 || r2; 
    } 
+0

Добро пожаловать в переполнение стека! В то время как вы, возможно, решили проблему афера, ответы только на код не очень помогают другим, которые сталкиваются с этим вопросом. Измените свой ответ, чтобы объяснить, почему ваш код решает исходную проблему. –

-2

C# консольного пример приложения

Командная строка Пример:
C : /> App_Exe -Opy PythonFile.py 1 2 3
Консольный выход:
Список аргументов: -Opy PythonFile.py 1 2 3
Найдено питон файла: PythonFile.py

using System; 
using System.Text.RegularExpressions;   //Regex 

namespace ConsoleApp1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string cmdLine = String.Join(" ", args); 

      bool bFileExtFlag = false; 
      int argIndex = 0; 
      Regex regex; 
      foreach (string s in args) 
      { 
       //Search for the 1st occurrence of the "*.py" pattern 
       regex = new Regex(@"(?s:.*)\056py", RegexOptions.IgnoreCase); 
       bFileExtFlag = regex.IsMatch(s); 
       if (bFileExtFlag == true) 
        break; 
       argIndex++; 
      }; 

      Console.WriteLine("Argument list: " + cmdLine); 
      if (bFileExtFlag == true) 
       Console.WriteLine("Found python filename: " + args[argIndex]); 
      else 
       Console.WriteLine("Python file with extension <.py> not found!"); 
     } 


    } 
} 
+0

Итак, вы решаете проблему с внешним приложением? вы понимаете, сколько ненужных ресурсов потрачено впустую? – NucS

+0

@NucS Я думаю, что мы должны проанализировать код и выяснить, что полезно. Во всяком случае, я не вижу, что это приводит к другим ответам. – Jerther

Смежные вопросы