string 在字符串中搜索字符串的简单方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/782911/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 00:26:02  来源:igfitidea点击:

Easy way to search a string for strings

stringsearchc#-2.0

提问by rahkim

I'm trying to find the easiest way to search a stringfor an array of possible strings. I know the easy way to do this for characters is to use myString.IndexOfAny(charArray). But how what if I'd like to search my stringfor strings and not just characters? Are there any .net tricks or methods that make this easier?

我试图找到最简单的方法来搜索string可能的strings数组。我知道对字符执行此操作的简单方法是使用myString.IndexOfAny(charArray). 但是如果我想搜索我stringstrings 而不仅仅是字符怎么办?是否有任何 .net 技巧或方法可以使这更容易?

Basically, I'd like to do something like this:

基本上,我想做这样的事情:

string myName = "rahkim";
string[] names = new string[] {"joe","bob","chris"};

if(myName.IndexOfAny(names) >= 0)
{
      //success code//
}

I know there are ways to do this with loops, etc. But I was hoping for something inherent in the framework.

我知道有一些方法可以用循环等来做到这一点。但我希望框架中固有的东西。

回答by Samuel

You should define if you want to to find equal strings or search for a matching substring. Both ways are easy pre-LINQ and with LINQ.

您应该定义是要查找相等的字符串还是搜索匹配的子字符串。这两种方式在 LINQ 之前和使用 LINQ 都很简单。

string myName = "rahkim";
string[] names = new string[] { "joe", "bob", "chris" };
等号字符串,LINQ
bool contains = names.Contains(myName);
等号字符串,LINQ 之前
bool contains = new List<string>(name).Contains(myName);
子字符串,LINQ
bool contains = names.Any(name => name.Contains(myName));
子串,预 LINQ
bool contains = false;
foreach(string name in names)
  if (name.Contains(myName))
    contains = true;

回答by Laurence

If anyone else found this while trying to search for a .Net method like String.IndexOfAny(String[]), this is my solution:

如果其他人在尝试搜索像 String.IndexOfAny(String[]) 这样的 .Net 方法时发现了这个,这是我的解决方案:

C#

C#

public int IndexOfAny(string test, string[] values)
{
int first = -1;
foreach (string item in values) {
    int i = test.IndexOf(item);
    if (i >= 0) {
        if (first > 0) {
            if (i < first) {
                first = i;
            }
        } else {
            first = i;
        }
    }
}
return first;
}

VB

VB

Public Function IndexOfAny(test As String, values As String()) As Integer
        Dim first As Integer = -1
        For Each item As String In values
            Dim i As Integer = test.IndexOf(item)
            If i >= 0 Then
                If first > 0 Then
                    If i < first Then
                        first = i
                    End If
                Else
                    first = i
                End If
            End If
        Next
        Return first
    End Function

You can do a LastIndexOfAny(String[]) by just switching the

你可以做一个 LastIndexOfAny(String[]) 只需切换

i < first 

to

i > first

回答by Pat

You can (also) use the staticIndexOfmethod of the Arrayclass:

您可以(也)使用该类的staticIndexOf方法Array

bool hasName = Array.IndexOf(names, myName) > -1;

回答by Glenn Slayden

int IndexOfAny(String[] rgs)would indeed be nice but it's nominally an O(n^2) operation. If, in your application, the set of strings rgsis large and always the same, the most efficient approach is to load them into a triedata structure once, and then use the trie repeatedly to search for them within the unknown strings given at runtime.

int IndexOfAny(String[] rgs)确实很好,但它名义上是 O(n^2) 操作。如果在您的应用程序中,字符串集rgs很大且始终相同,最有效的方法是将它们加载到一个trie数据结构中一次,然后重复使用 trie 在运行时给出的未知字符串中搜索它们.

Here is the relevant code, adapted from a C# trie source I found on the web, attributed to "Kerry D. Wong." In my version, each string in the trie has a "payload" of generic type TValue. To use this trie to simply search for substrings, the payload could always be set to true, as illustrated with simple_trie.

这是相关代码,改编自我在网上找到的 C# trie 源代码,作者为“Kerry D. Wong”。在我的版本中,trie 中的每个字符串都有一个泛型类型TValue的“有效负载” 。要使用此 trie 来简单地搜索子字符串,可以始终将有效负载设置为true,如simple_trie 所示

The other thing I changed here is that this trie automatically adapts allow for storage of arbitrary Unicode strings. The array at each node—which characterizes a trie—adjusts its base and length to accomodate the range of Unicode characters which need to be stored at that node. This allows for case-sensitive matching, for example.

我在这里更改的另一件事是该树会自动适应允许存储任意 Unicode 字符串。每个节点上的数组(表征特里树)调整其基数和长度以适应需要存储在该节点的 Unicode 字符范围。例如,这允许区分大小写的匹配。

The C# 3.0 initialization syntax is handy for this trie, but enabling it requires a dummy implementation of IEnumerablein order to compile. The CLR doesn't seem to call GetEnumerator() and I suggest that you don't try to enumerate with its result either.

C# 3.0 初始化语法对于这个特里很方便,但启用它需要IEnumerable的虚拟实现才能编译。CLR 似乎没有调用 GetEnumerator(),我建议您也不要尝试使用其结果进行枚举。

using System;
using System.Collections.Generic;
using System.Linq;  // only used in Main()

class Program
{
    // trie with payload of type <String>
    static Trie<String> value_trie = new Trie<String>
    {
        { "rabbit", "cute" },
        { "giraffe", "tall" },
        { "ape", "smart" },
        { "hippo", "large" },
    };

    // degenerate case of a trie without payload
    static Trie<bool> simple_trie = new Trie<bool>
    {
        { "rabbit", true },
        { "giraffe", true },
        { "ape", true },
        { "hippo", true },
    };

    static void Main(String[] args)
    {
        String s = "Once upon a time, a rabbit met an ape in the woods.";

        // Retrieve payloads for words in the string.
        //
        // output:
        //      cute
        //      smart
        foreach (String word in value_trie.AllSubstringValues(s))
            Console.WriteLine(word);

        // Simply test a string for any of the words in the trie.
        // Note that the Any() operator ensures that the input is no longer
        // traversed once a single result is found.
        //
        // output:
        //      True
        Console.WriteLine(simple_trie.AllSubstringValues(s).Any(e=>e));

        s = "Four score and seven years ago.";
        // output:
        //      False
        Console.WriteLine(simple_trie.AllSubstringValues(s).Any(e => e));
    }
}

class TrieNode<TValue>
{
    private TrieNode<TValue>[] nodes = null;
    private TValue m_value = default(TValue);
    private Char m_base;

    public Char Base { get { return m_base; } }
    public bool IsEnd { get { return !m_value.Equals(default(TValue)); } }

    public TValue Value
    {
        get { return m_value; }
        set { m_value = value; }
    }

    public IEnumerable<TrieNode<TValue>> Nodes { get { return nodes; } }

    public TrieNode<TValue> this[char c]
    {
        get
        {
            if (nodes != null && m_base <= c && c < m_base + nodes.Length)
                return nodes[c - m_base];
            return null;
        }
    }

    public TrieNode<TValue> AddChild(char c)
    {
        if (nodes == null)
        {
            m_base = c;
            nodes = new TrieNode<TValue>[1];
        }
        else if (c >= m_base + nodes.Length)
        {
            Array.Resize(ref nodes, c - m_base + 1);
        }
        else if (c < m_base)
        {
            Char c_new = (Char)(m_base - c);
            TrieNode<TValue>[] tmp = new TrieNode<TValue>[nodes.Length + c_new];
            nodes.CopyTo(tmp, c_new);
            m_base = c;
            nodes = tmp;
        }

        TrieNode<TValue> node = nodes[c - m_base];
        if (node == null)
        {
            node = new TrieNode<TValue>();
            nodes[c - m_base] = node;
        }
        return node;
    }
};

class Trie<TValue> : System.Collections.IEnumerable
{
    private TrieNode<TValue> _root = new TrieNode<TValue>();

    // This dummy enables C# 3.0 initialization syntax
    public System.Collections.IEnumerator GetEnumerator()
    {
        return null;
    }

    public void Add(String s, TValue v)
    {
        TrieNode<TValue> node = _root;
        foreach (Char c in s)
            node = node.AddChild(c);

        node.Value = v;
    }

    public bool Contains(String s)
    {
        TrieNode<TValue> node = _root;
        foreach (Char c in s)
        {
            node = node[c];
            if (node == null)
                return false;
        }
        return node.IsEnd;
    }

    public TValue Find(String s_in)
    {
        TrieNode<TValue> node = _root;
        foreach (Char c in s_in)
        {
            node = node[c];
            if (node == null)
                return default(TValue);
        }
        return node.Value;
    }

    public IEnumerable<TValue> FindAll(String s_in)
    {
        TrieNode<TValue> node = _root;
        foreach (Char c in s_in)
        {
            node = node[c];
            if (node == null)
                break;
            if (node.Value != null)
                yield return node.Value;
        }
    }

    public IEnumerable<TValue> AllSubstringValues(String s)
    {
        int i_cur = 0;
        while (i_cur < s.Length)
        {
            TrieNode<TValue> node = _root;
            int i = i_cur;
            while (i < s.Length)
            {
                node = node[s[i]];
                if (node == null)
                    break;
                if (node.Value != null)
                    yield return node.Value;
                i++;
            }
            i_cur++;
        }
    }
};

回答by Jose Basilio

Here's the right syntax:

这是正确的语法:

if(names.Contains(myName))
{
      //success code//
}

回答by TStamper

if (names.Contains(myName)) 
{
//success code//
}