我正在尝试找到在
string
中搜索可能的 string
数组的最简单方法。我知道对角色执行此操作的简单方法是使用 myString.IndexOfAny(charArray)
。但是,如果我想在 string
中搜索 string
而不仅仅是字符怎么办?有没有任何 .net 技巧或方法可以让这变得更容易?
基本上,我想做这样的事情:
string myName = "rahkim";
string[] names = new string[] {"joe","bob","chris"};
if(myName.IndexOfAny(names) >= 0)
{
//success code//
}
我知道有一些方法可以通过循环等来做到这一点。但我希望框架中有一些固有的东西。
您应该定义是否要查找相等的字符串或搜索匹配的子字符串。在使用 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;
如果其他人在尝试搜索像 String.IndexOfAny(String[]) 这样的 .Net 方法时发现了这个,这是我的解决方案:
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
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
您只需切换
即可执行 LastIndexOfAny(String[])i < first
到
i > first
您也可以使用
static
类的 IndexOf
Array
方法:
bool hasName = Array.IndexOf(names, myName) > -1;
int IndexOfAny(String[] rgs) 确实很好,但名义上它是一个 O(n^2) 操作。如果在您的应用程序中,字符串集 rgs 很大并且始终相同,最有效的方法是将它们加载到 trie 数据结构中一次,然后重复使用 trie 在未知中搜索它们运行时给出的字符串。
这里是相关代码,改编自我在网上找到的 C# trie 源代码,作者为“Kerry D. Wong”。在我的版本中,特里树中的每个字符串都有一个通用类型TValue的“有效负载”。要使用此 trie 来简单地搜索子字符串,有效负载始终可以设置为 true,如 simple_trie 所示。
我在这里改变的另一件事是这个 trie 自动适应允许存储任意 Unicode 字符串。每个节点处的数组(表征 trie)会调整其基数和长度以适应需要存储在该节点处的 Unicode 字符的范围。例如,这允许区分大小写的匹配。
C# 3.0 初始化语法对于此 trie 来说很方便,但启用它需要 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++;
}
}
};
这是正确的语法:
if(names.Contains(myName))
{
//success code//
}
if (names.Contains(myName))
{
//success code//
}
可能更短的代码是:
int indexOfAny = Math.Min(url.IndexOf("?"), url.IndexOf("#"));
// if (i > -1)
// url = url.Substring(0, i);