Как извлечь фразы, а затем слова в строке текста?

У меня есть метод поиска, который принимает введенную пользователем строку, разбивает ее на каждый символ пробела, а затем переходит к поиску совпадений на основе списка разделенных терминов:

string[] terms = searchTerms.ToLower().Trim().Split( ' ' );

Теперь мне поставили еще одно требование: иметь возможность искать фразы через разделители в двойных кавычках а-ля Google. Итак, если бы условия поиска были:

"строка" текста

Поиск будет соответствовать вхождениям «строки» и «текста», а не четырем отдельным терминам [перед поиском также необходимо будет удалить открывающие и закрывающие двойные кавычки].

Как я могу добиться этого на С#? Я бы предположил, что регулярные выражения - это то, что нужно, но я не баловался ими, поэтому не знаю, являются ли они лучшим решением.

Если вам нужна дополнительная информация, пожалуйста, спросите. Заранее спасибо за помощь.


person Rich    schedule 09.09.2009    source источник
comment
Что вы пытаетесь сделать с результатом поиска? Под извлечением вы подразумеваете, что хотите удалить условия поиска из текста, который вы ищете?   -  person womp    schedule 09.09.2009


Ответы (6)


Вот шаблон регулярного выражения, который будет возвращать совпадения в группах с именем «term»:

("(?<term>[^"]+)"\s*|(?<term>[^ ]+)\s*)+

Итак, для ввода:

"a line" of text

Выходными элементами, идентифицированными группой «term», будут:

a line
of
text
person Drew Noakes    schedule 09.09.2009
comment
Эй.. это не работает для меня. string pattern1 = (\(?‹term›[^\]+)\; string pattern2= @\s*|(?‹term›[^ ]+)\s*)+; шаблон строки = шаблон1 + шаблон2; Regex rgx = новое регулярное выражение (шаблон); Match match = rgx.Match(SearchText); - person GorvGoyl; 04.01.2016
comment
Как я могу получить массив из этого термина на основе регулярного выражения? - person GorvGoyl; 04.01.2016

Регулярные выражения определенно подойдут...

Вы должны проверить эту ссылку MSDN для получения некоторой информации о классе Regex: http://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex.aspx

а вот отличная ссылка для изучения синтаксиса регулярных выражений: http://www.radsoftware.com.au/articles/regexlearnsyntax.aspx

Затем, чтобы добавить несколько примеров кода, вы можете сделать что-то вроде этого:

string searchString = "a line of";

Match m = Regex.Match(textToSearch, searchString);

или если вы просто хотите узнать, содержит ли строка совпадение или нет:

bool success = Regex.Match(textToSearch, searchString).Success;
person Robban    schedule 09.09.2009

используйте построитель регулярных выражений здесь

http://gskinner.com/RegExr/

и вы сможете манипулировать регулярным выражением так, как вам нужно.

person Craig Angus    schedule 09.09.2009

Используйте регулярные выражения....

string textToSearchIn = ""строка" текста";
string result = Regex.Match(textToSearchIn, "(?‹=").*?(?=")").Value;

или, если их больше одного, поместите это в коллекцию совпадений...

MatchCollection allPhrases = Regex.Matches(textToSearchIn, "(?‹=").*?(?=")");

person xoxo    schedule 09.09.2009

Knuth-Morris-Pratt (KMP алгоритм) признан самым быстрым алгоритмом поиска подстрок в строках (ну, технически не строк, а массивов байтов).

using System.Collections.Generic;

namespace KMPSearch
{
    public class KMPSearch
    {
        public static int NORESULT = -1;

        private string _needle;
        private string _haystack;
        private int[] _jumpTable;

        public KMPSearch(string haystack, string needle)
        {
            Haystack = haystack;
            Needle = needle;
        }

        public void ComputeJumpTable()
        {
            //Fix if we are looking for just one character...
            if (Needle.Length == 1)
            {
                JumpTable = new int[1] { -1 };
            }
            else
            {
                int needleLength = Needle.Length;
                int i = 2;
                int k = 0;

                JumpTable = new int[needleLength];
                JumpTable[0] = -1;
                JumpTable[1] = 0;

                while (i <= needleLength)
                {
                    if (i == needleLength)
                    {
                        JumpTable[needleLength - 1] = k;
                    }
                    else if (Needle[k] == Needle[i])
                    {
                        k++;
                        JumpTable[i] = k;
                    }
                    else if (k > 0)
                    {
                        JumpTable[i - 1] = k;
                        k = 0;
                    }

                    i++;
                }
            }
        }

        public int[] MatchAll()
        {
            List<int> matches = new List<int>();
            int offset = 0;
            int needleLength = Needle.Length;
            int m = Match(offset);

            while (m != NORESULT)
            {
                matches.Add(m);
                offset = m + needleLength;
                m = Match(offset);
            }

            return matches.ToArray();
        }

        public int Match()
        {
            return Match(0);
        }

        public int Match(int offset)
        {
            ComputeJumpTable();

            int haystackLength = Haystack.Length;
            int needleLength = Needle.Length;

            if ((offset >= haystackLength) || (needleLength > ( haystackLength - offset))) 
                return NORESULT;

            int haystackIndex = offset;
            int needleIndex = 0;

            while (haystackIndex < haystackLength)
            {
                if (needleIndex >= needleLength)
                    return haystackIndex;

                if (haystackIndex + needleIndex >= haystackLength)
                    return NORESULT;

                if (Haystack[haystackIndex + needleIndex] == Needle[needleIndex])
                {
                    needleIndex++;
                } 
                    else
                {
                    //Naive solution
                    haystackIndex += needleIndex;

                    //Go back
                    if (needleIndex > 1)
                    {
                        //Index of the last matching character is needleIndex - 1!
                        haystackIndex -= JumpTable[needleIndex - 1];
                        needleIndex = JumpTable[needleIndex - 1];
                    }
                    else
                        haystackIndex -= JumpTable[needleIndex];


                }
            }

            return NORESULT;
        }

        public string Needle
        {
            get { return _needle; }
            set { _needle = value; }
        }

        public string Haystack
        {
            get { return _haystack; }
            set { _haystack = value; }
        }

        public int[] JumpTable
        {
            get { return _jumpTable; }
            set { _jumpTable = value; }
        }
    }
}

Применение :-

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace KMPSearch
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length != 2)
            {
                Console.WriteLine("Usage: " + Environment.GetCommandLineArgs()[0] + " haystack needle");
            }
            else
            {
                KMPSearch search = new KMPSearch(args[0], args[1]);
                int[] matches = search.MatchAll();
                foreach (int i in matches)
                    Console.WriteLine("Match found at position " + i+1);
            }
        }

    }
}
person Rob Cowell    schedule 09.09.2009

Попробуйте это, он вернет массив для текста. пример: { "строка" текста "блокнот" }:

string textToSearch = "\"a line of\" text \" notepad\"";

MatchCollection allPhrases = Regex.Matches(textToSearch, "(?<=\").*?(?=\")");

var RegArray = allPhrases.Cast<Match>().ToArray();

вывод: {"строка","текст","блокнот" }

person GorvGoyl    schedule 04.01.2016