programing

C#에서 더 큰 문자열에서 하위 문자열의 모든 위치 찾기

powerit 2023. 6. 17. 09:46
반응형

C#에서 더 큰 문자열에서 하위 문자열의 모든 위치 찾기

분석해야 할 큰 , 구문분야하큰문있이으의 모든 .extract"(me,i-have lots. of]punctuation목록에 각 인덱스를 저장합니다.

의 시작 부분에 하면, 다 이고, 는 서이조중있가면정하시고작과, 두개모발다추것다니입될가, 추가될 것입니다.List 리고그고.List을포할 것다니입을 할 수 .0그리고 다른 인덱스가 무엇이든 간에.

놀고 속놀있었데는고그, 리고계▁i.string.IndexOf거의 제가 찾고 있는 것을 수행하고 코드를 작성했습니다. 하지만 작동하지 않고 정확하게 무엇이 잘못되었는지 파악할 수 없었습니다.

List<int> inst = new List<int>();
int index = 0;
while (index < source.LastIndexOf("extract\"(me,i-have lots. of]punctuation", 0) + 39)
{
    int src = source.IndexOf("extract\"(me,i-have lots. of]punctuation", index);
    inst.Add(src);
    index = src + 40;
}
  • inst 목록
  • source 문자열 큰

더 좋은 생각은 없습니까?

다음은 확장 방법의 예입니다.

public static List<int> AllIndexesOf(this string str, string value) {
    if (String.IsNullOrEmpty(value))
        throw new ArgumentException("the string to find may not be empty", "value");
    List<int> indexes = new List<int>();
    for (int index = 0;; index += value.Length) {
        index = str.IndexOf(value, index);
        if (index == -1)
            return indexes;
        indexes.Add(index);
    }
}

이것을 정적 클래스에 넣고 네임스페이스를 가져오는 경우using모든 문자열에 메소드로 표시되며 다음 작업을 수행할 수 있습니다.

List<int> indexes = "fooStringfooBar".AllIndexesOf("foo");

확장 방법에 대한 자세한 내용은 http://msdn.microsoft.com/en-us/library/bb383977.aspx 을 참조하십시오.

또한 반복기를 사용하는 경우에도 마찬가지입니다.

public static IEnumerable<int> AllIndexesOf(this string str, string value) {
    if (String.IsNullOrEmpty(value))
        throw new ArgumentException("the string to find may not be empty", "value");
    for (int index = 0;; index += value.Length) {
        index = str.IndexOf(value, index);
        if (index == -1)
            break;
        yield return index;
    }
}

기본 제공되는 ReGEx 클래스를 사용해 보십시오.

public static IEnumerable<int> GetAllIndexes(this string source, string matchString)
{
   matchString = Regex.Escape(matchString);
   foreach (Match match in Regex.Matches(source, matchString))
   {
      yield return match.Index;
   }
}

표현식을 다시 사용해야 하는 경우 컴파일하여 어딘가에 캐시합니다.재사용 사례에 대한 다른 오버로드에서 matchString 매개 변수를 Regex matchExpression으로 변경합니다.

LINQ 사용

public static IEnumerable<int> IndexOfAll(this string sourceString, string subString)
{
    return Regex.Matches(sourceString, subString).Cast<Match>().Select(m => m.Index);
}

광택 버전 + 지원 무시 사례:

public static int[] AllIndexesOf(string str, string substr, bool ignoreCase = false)
{
    if (string.IsNullOrWhiteSpace(str) ||
        string.IsNullOrWhiteSpace(substr))
    {
        throw new ArgumentException("String or substring is not specified.");
    }

    var indexes = new List<int>();
    int index = 0;

    while ((index = str.IndexOf(substr, index, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) != -1)
    {
        indexes.Add(index++);
    }

    return indexes.ToArray();
}

O(N + M)에서 KMP 알고리즘을 사용하여 효율적인 시간 복잡도에서 수행할 수 있습니다. 여기서 N은 다음의 길이입니다.text은 그고은 M길니다이의 입니다.pattern.

다음은 구현 및 사용 방법입니다.

static class StringExtensions
{
    public static IEnumerable<int> AllIndicesOf(this string text, string pattern)
    {
        if (string.IsNullOrEmpty(pattern))
        {
            throw new ArgumentNullException(nameof(pattern));
        }
        return Kmp(text, pattern);
    }

    private static IEnumerable<int> Kmp(string text, string pattern)
    {
        int M = pattern.Length;
        int N = text.Length;

        int[] lps = LongestPrefixSuffix(pattern);
        int i = 0, j = 0; 

        while (i < N)
        {
            if (pattern[j] == text[i])
            {
                j++;
                i++;
            }
            if (j == M)
            {
                yield return i - j;
                j = lps[j - 1];
            }

            else if (i < N && pattern[j] != text[i])
            {
                if (j != 0)
                {
                    j = lps[j - 1];
                }
                else
                {
                    i++;
                }
            }
        }
    }

    private static int[] LongestPrefixSuffix(string pattern)
    {
        int[] lps = new int[pattern.Length];
        int length = 0;
        int i = 1;

        while (i < pattern.Length)
        {
            if (pattern[i] == pattern[length])
            {
                length++;
                lps[i] = length;
                i++;
            }
            else
            {
                if (length != 0)
                {
                    length = lps[length - 1];
                }
                else
                {
                    lps[i] = length;
                    i++;
                }
            }
        }
        return lps;
    }

다음은 사용 방법의 예입니다.

static void Main(string[] args)
    {
        string text = "this is a test";
        string pattern = "is";
        foreach (var index in text.AllIndicesOf(pattern))
        {
            Console.WriteLine(index); // 2 5
        }
    }

적어도 두 개의 제안된 솔루션이 중복된 검색 검색을 처리하지 않는다는 것을 알게 되었습니다.저는 녹색 체크 표시가 된 것을 확인하지 못했습니다.다음은 중복 검색 히트를 처리하는 방법입니다.

    public static List<int> GetPositions(this string source, string searchString)
    {
        List<int> ret = new List<int>();
        int len = searchString.Length;
        int start = -1;
        while (true)
        {
            start = source.IndexOf(searchString, start +1);
            if (start == -1)
            {
                break;
            }
            else
            {
                ret.Add(start);
            }
        }
        return ret;
    }

정규식이 없는 경우 문자열 비교 유형 사용:

string search = "123aa456AA789bb9991AACAA";
string pattern = "AA";
Enumerable.Range(0, search.Length)
   .Select(index => { return new { Index = index, Length = (index + pattern.Length) > search.Length ? search.Length - index : pattern.Length }; })
   .Where(searchbit => searchbit.Length == pattern.Length && pattern.Equals(search.Substring(searchbit.Index, searchbit.Length),StringComparison.OrdinalIgnoreCase))
   .Select(searchbit => searchbit.Index)

{3,8,19,22}을(를) 반환합니다.빈 패턴은 모든 위치와 일치합니다.

여러 패턴의 경우:

string search = "123aa456AA789bb9991AACAA";
string[] patterns = new string[] { "aa", "99" };
patterns.SelectMany(pattern => Enumerable.Range(0, search.Length)
   .Select(index => { return new { Index = index, Length = (index + pattern.Length) > search.Length ? search.Length - index : pattern.Length }; })
   .Where(searchbit => searchbit.Length == pattern.Length && pattern.Equals(search.Substring(searchbit.Index, searchbit.Length), StringComparison.OrdinalIgnoreCase))
   .Select(searchbit => searchbit.Index))

{3, 8, 19, 22, 15, 16}을(를) 반환합니다.

public List<int> GetPositions(string source, string searchString)
{
    List<int> ret = new List<int>();
    int len = searchString.Length;
    int start = -len;
    while (true)
    {
        start = source.IndexOf(searchString, start + len);
        if (start == -1)
        {
            break;
        }
        else
        {
            ret.Add(start);
        }
    }
    return ret;
}

다음과 같이 부릅니다.

List<int> list = GetPositions("bob is a chowder head bob bob sldfjl", "bob");
// list will contain 0, 22, 26

안녕하세요, @Matti Virkkunen의 좋은 답변입니다.

public static List<int> AllIndexesOf(this string str, string value) {
    if (String.IsNullOrEmpty(value))
        throw new ArgumentException("the string to find may not be empty", "value");
    List<int> indexes = new List<int>();
    for (int index = 0;; index += value.Length) {
        index = str.IndexOf(value, index);
        if (index == -1)
            return indexes;
        indexes.Add(index);
        index--;
    }
}

하지만 여기에는 AOOAOOA와 같은 테스트 사례가 포함됩니다.

AOOA 및 AOOA입니다.

출력 0 및 3

@csam은 이론적으로 정확하지만, 그의 코드는 준수하지 않을 것이고 굴절될 수 있습니다.

public static IEnumerable<int> IndexOfAll(this string sourceString, string matchString)
{
    matchString = Regex.Escape(matchString);
    return from Match match in Regex.Matches(sourceString, matchString) select match.Index;
}
public static Dictionary<string, IEnumerable<int>> GetWordsPositions(this string input, string[] Susbtrings)
{
    Dictionary<string, IEnumerable<int>> WordsPositions = new Dictionary<string, IEnumerable<int>>();
    IEnumerable<int> IndexOfAll = null;
    foreach (string st in Susbtrings)
    {
        IndexOfAll = Regex.Matches(input, st).Cast<Match>().Select(m => m.Index);
        WordsPositions.Add(st, IndexOfAll);

    }
    return WordsPositions;
}

더 큰 문자열 내에서 문자열의 여러 인스턴스를 찾는 데 사용한 코드에 따르면 코드는 다음과 같습니다.

List<int> inst = new List<int>();
int index = 0;
while (index >=0)
{
    index = source.IndexOf("extract\"(me,i-have lots. of]punctuation", index);
    inst.Add(index);
    index++;
}

예제를 찾아 함수에 통합했습니다.

    public static int solution1(int A, int B)
    {
        // Check if A and B are in [0...999,999,999]
        if ( (A >= 0 && A <= 999999999) && (B >= 0 && B <= 999999999))
        {
            if (A == 0 && B == 0)
            {
                return 0;
            }
            // Make sure A < B
            if (A < B)
            {                    
                // Convert A and B to strings
                string a = A.ToString();
                string b = B.ToString();
                int index = 0;

                // See if A is a substring of B
                if (b.Contains(a))
                {
                    // Find index where A is
                    if (b.IndexOf(a) != -1)
                    {                            
                        while ((index = b.IndexOf(a, index)) != -1)
                        {
                            Console.WriteLine(A + " found at position " + index);
                            index++;
                        }
                        Console.ReadLine();
                        return b.IndexOf(a);
                    }
                    else
                        return -1;
                }
                else
                {
                    Console.WriteLine(A + " is not in " + B + ".");
                    Console.ReadLine();

                    return -1;
                }
            }
            else
            {
                Console.WriteLine(A + " must be less than " + B + ".");
               // Console.ReadLine();

                return -1;
            }                
        }
        else
        {
            Console.WriteLine("A or B is out of range.");
            //Console.ReadLine();

            return -1;
        }
    }

    static void Main(string[] args)
    {
        int A = 53, B = 1953786;
        int C = 78, D = 195378678;
        int E = 57, F = 153786;

        solution1(A, B);
        solution1(C, D);
        solution1(E, F);

        Console.WriteLine();
    }

반환:

2번 위치에서 53개 발견

위치 4에서 78개 발견
7번 위치에서 78개 발견

57은 153786에 없습니다.

대체 구현 방법은 무엇입니까?

 public static class MyExtensions
    {
        public static int HowMany(this string str, char needle)
        {
            int counter = 0;
            int nextIndex = 0;
            for (; nextIndex != -1; )
            {
                nextIndex = str.IndexOf(needle, nextIndex);
                if (nextIndex != -1)
                {
                    counter++;
                    //step over to the next char
                    nextIndex++;
                }
            }
            return counter;
        }
    }

linq를 사용하여 모든 요소를 선택하고 열거한 다음 임의의 문자열로 찾을 수 있습니다.

클래스를 만들었습니다.

class Pontos 
{
    //index on string
    public int Pos { get; set; }
    //caractere 
    public string Caractere { get; set; }           
}

다음과 같이 사용합니다.

int count = 0;

var pontos = texto.Select(y => new Pontos { Pos = count++, Caractere = y.ToString() }).Where(x=>x.Caractere == ".").ToList();

다음: 입력 문자열:

출력 목록:

PS:SeForNumero제 수업의 또 다른 분야입니다. 저는 이것이 제 자신의 목적을 위해 필요하지만, 이 사용에 필요하지 않습니다.

언급URL : https://stackoverflow.com/questions/2641326/finding-all-positions-of-substring-in-a-larger-string-in-c-sharp

반응형