改变方法,以使他们的搜索变得不敏感



我有两种我需要修复的方法,以便当用户搜索" javaScript"时,如果它们拼写为" javascript"或喜欢" javascript",则方法将返回值。 - 资本化无关紧要。LoadData()已经完成了从CSV文件中导入数据(该方法执行其搜索)。可以在此处找到我正在使用的三个文件(jobdata.cs,program.cs,job_data.csv)的完整代码。

我需要修复的第一种方法是此方法(在Jobdata.cs,第143行中找到):

 public static List<Dictionary<string, string>> FindByValue(string searchTerm)
    {
        LoadData();
        //set up a list of jobs that we're going to use to return from this method
        List<Dictionary<string, string>> jobs = new List<Dictionary<string, string>>();
        //row is a Dictionary<string, string>
        foreach (Dictionary<string, string> row in AllJobs)
        {
            //item is a KeyValuePair
            foreach (KeyValuePair<string, string> field in row)
            {
                string aValue = field.Value;
                if (aValue.Contains(searchTerm))
                {
                    jobs.Add(row);
                    break;
                }
            }
        }
        return jobs;
    }  

也许做到这一点的一种方法是打破 searchTerm s和 value s向下,以便在用户搜索时它们会自动成为小写。这样,即使用户键入JavaScript,它也会自动变成JavaScript,并且它将匹配字符串field中的字符,该字符也将成为小写。当然,无论是" JavaScript"还是" JavaScript",我们仍将返回字段中的原始字符串。

做到这一点的另一种方法是自动使searchTerm情况不敏感,以便与field.Value匹配,无论大写如何。

这样做看起来像这样吗?

  public static List<Dictionary<string, string>> FindByValue(string searchTerm)
    {
        LoadData();
        //set up a list of jobs that we're going to use to return from this method
        List<Dictionary<string, string>> jobs = new List<Dictionary<string, string>>();
        //row is a Dictionary<string, string>
        foreach (Dictionary<string, string> row in AllJobs)
        {
            //item is a KeyValuePair
            foreach (KeyValuePair<string, string> field in row)
            {
                string aValue = field.Value;
                //create new, case-insensitive searchTerm
                culture.CompareInfo.IndexOf(searchTerm, aValue, CompareOptions.IgnoreCase) >= 0
                if (aValue.Contains(searchTerm))
                {
                    jobs.Add(row);
                    break;
                }
            }
        }
        return jobs;
    }   

我正在尝试使用此示例不敏感的字符串比较。但是使用该行会给我错误消息:

The name "culture" does not exist in the current context
The name "CompareOptions" does not exist in the current context

field.aValue相比,我如何对searchTerms不敏感的情况不敏感?

您使用IndexOf代替Contains的想法是正确的,您只需使用正确的过载(采用StringComparison选项的一个)即可。对病例不敏感的比较有多种选择。我正在使用OrdinalIgnoreCase,但是您可以使用最适合您的一种。

而不是这样:

aValue.Contains(searchTerm)

写下:

aValue.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0

让我们首先说您不能比较字符串,并且没有使案例敏感的字符串。它们总是因为大写和小写字母具有不同的Unicode值。这是您的解决方案:

如果要盖帽检查每个字符串,则可以使用ToUpper()ToLower()方法。例如:

string s1 = "JavaScript";
string s2 = "Javascript";
if (s1.ToLower() == s2.ToLower())
{
    //Do something
}

它也可以与ToUpper()一起使用,因为:

//s1.ToLower() == "javascript";
//s1.ToUpper() == "JAVASCRIPT";

因此,它与您的情况有关,假设您的Dictionary充满了所有小写字符串,您可以简单地说:

if (aValue.Contains(searchTerm.ToLower()))
{
    //Do something
}

有关这些功能的更多信息,请查看

https://msdn.microsoft.com/en-us/library/e78f86at(v = vs.110).aspx
和https://msdn.microsoft.com/en-us/library/system.stem.toupper(v = vs.110).aspx

多年来,我已经玩过了一点,我能想到的最强大的解决方案是创建一个类似于String的包装器,它可以在一种不敏感的方式。尽管取决于您的需求,但这可能是过度杀人的...

用法是:

using StringOrdinalIgnoreCase = JDanielSmith.System.String<JDanielSmith.System.OrdinalIgnoreCase>;
[TestMethod]
public void StringOrdinalIgnoreCaseDictionary()
{
    var d = new Dictionary<StringOrdinalIgnoreCase, int>() { { "abc", 1 }, { "def", 2 } };
    Assert.IsTrue(d.ContainsKey("ABC"));
    try
    {
        d.Add("DEF", 2);
        Assert.Fail();
    }
    catch (ArgumentException) { }
}

String.cs

using System;
using CodeAnalysis = System.Diagnostics.CodeAnalysis;
namespace MyNS.System
{
    /// <summary>
    /// Provide a case-insensitive wrapper around System.String.
    /// 
    /// This is especially useful when using strings as keys in collections, where the key is something like a Windows file-system pathname;
    /// it can be easy to forget to pass an IEqualityComparer<> in the constructor.
    /// 
    /// Some hints from: http://stackoverflow.com/questions/33039324/how-can-system-string-be-properly-wrapped-for-case-insensitivy
    /// </summary>
    [CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "String")]
    [CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1036:OverrideMethodsOnComparableTypes")]
    public sealed class String<TComparerAndComparison> : IComparable, ICloneable,
        IComparable<String<TComparerAndComparison>>, IEquatable<String<TComparerAndComparison>>,
        IComparable<String>, IEquatable<String>
        where TComparerAndComparison : StringComparerAndComparison, new()
    {
        static readonly StringComparerAndComparison _comparerAndComparison = new TComparerAndComparison();
        static readonly StringComparer _comparer = _comparerAndComparison.Comparer;
        static readonly StringComparison _comparisonType = _comparerAndComparison.Comparison;
        public string Value { get; }
        public String(string value)
        {
            // matching the behavior of System.String is more straight-forward if "Value" is never null
            Value = value ?? String.Empty;
        }
        // easily convert to/from System.String
        public static implicit operator String<TComparerAndComparison>(string source) => new String<TComparerAndComparison>(source);
        public static implicit operator string(String<TComparerAndComparison> source) => source?.Value;
        #region Equals, IEquatable
        public override bool Equals(object obj)
        {
            if (Object.ReferenceEquals(obj, null))
                return false; // this != null
            var other = obj as String<TComparerAndComparison>;
            if (!Object.ReferenceEquals(other, null))
                return Equals(other); // call Equals(String<TStringComparerAndComparison>)
            var s_other = obj as string;
            if (!Object.ReferenceEquals(s_other, null))
                return Equals(s_other); // call Equals(string)
            return _comparer.Equals(obj);
        }
        public bool Equals(String<TComparerAndComparison> other)
        {
            if (Object.ReferenceEquals(other, null))
                return false; // this != null
            return Equals(other.Value); // call Equals(string)
        }
        public bool Equals(string other) => _comparer.Equals(Value, other);
        public override int GetHashCode()
        {
            return _comparer.GetHashCode(Value);
        }
        #endregion
        public override string ToString() => Value;
        public object Clone() => new String<TComparerAndComparison>(Value);
        #region IComparable
        public int CompareTo(object obj)
        {
            // https://msdn.microsoft.com/en-us/library/4d7sx9hd(v=vs.110).aspx
            if (Object.ReferenceEquals(obj, null))
                return 1; // If other is not a valid object reference, this instance is greater.
            // obj must be either StringOrdinalIgnoreCase or String
            var other = obj as String<TComparerAndComparison>;
            if (Object.ReferenceEquals(other, null))
            {
                var s_other = obj as string;
                if (Object.ReferenceEquals(s_other, null))
                    throw new ArgumentException("Object must be of type " + nameof(String<TComparerAndComparison>) + " or String.");
                return CompareTo(s_other); // call CompareTo(string)
            }
            return CompareTo(other); // call CompareTo(StringOrdinalIgnoreCase)
        }
        public int CompareTo(String<TComparerAndComparison> other)
        {
            // https://msdn.microsoft.com/en-us/library/4d7sx9hd(v=vs.110).aspx
            if (Object.ReferenceEquals(other, null))
                return 1; // If other is not a valid object reference, this instance is greater.
            if (Object.ReferenceEquals(Value, other.Value))
                return 0;
            return CompareTo(other.Value); // call CompareTo(string)
        }
        public int CompareTo(string other)
        {
            // https://msdn.microsoft.com/en-us/library/4d7sx9hd(v=vs.110).aspx
            if (Object.ReferenceEquals(other, null))
                return 1; // If other is not a valid object reference, this instance is greater.
            return _comparer.Compare(Value, other);
        }
        public static bool operator ==(String<TComparerAndComparison> x, String<TComparerAndComparison> y)
        {
            if (Object.ReferenceEquals(x, null))
                return Object.ReferenceEquals(y, null); // null == null, null != something
            return x.Equals(y); // know x != null
        }
        public static bool operator ==(String<TComparerAndComparison> x, string y)
        {
            if (Object.ReferenceEquals(x, null))
                return Object.ReferenceEquals(y, null); // null == null, null != something
            return x.Equals(y); // know x != null
        }
        public static bool operator ==(string x, String<TComparerAndComparison> y) => y == x; // == is commutative, x == y
        public static bool operator !=(String<TComparerAndComparison> x, String<TComparerAndComparison> y) => !(x == y);
        public static bool operator !=(string x, String<TComparerAndComparison> y) => !(x == y);
        public static bool operator !=(String<TComparerAndComparison> x, string y) => !(x == y);
        #endregion
        #region IndexOf, LastIndexOf, StartsWith, EndsWith
        public bool EndsWith(string value) => Value.EndsWith(value, _comparisonType);
        public int IndexOf(string value) => Value.IndexOf(value, _comparisonType);
        public int IndexOf(string value, int startIndex) => Value.IndexOf(value, startIndex, _comparisonType);
        public int IndexOf(string value, int startIndex, int count) => Value.IndexOf(value, startIndex, count, _comparisonType);
        public int LastIndexOf(string value) => Value.LastIndexOf(value, _comparisonType);
        public int LastIndexOf(string value, int startIndex) => Value.LastIndexOf(value, startIndex, _comparisonType);
        public int LastIndexOf(string value, int startIndex, int count) => Value.LastIndexOf(value, startIndex, count, _comparisonType);
        public bool StartsWith(string value) => Value.StartsWith(value, _comparisonType);
        #endregion
    }
}

stringcomparerandcomparison.cs

using System;
using StringComparer = System.StringComparer;
using StringComparison = System.StringComparison;
namespace JDanielSmith.System
{
    /// <summary>
    /// Pass around System.StringComparer and System.StringComparison together.
    /// Also, provides a base class for generics.
    /// </summary>
    public abstract class StringComparerAndComparison
    {
        internal StringComparer Comparer { get; }
        internal StringComparison Comparison { get; }
        internal StringComparerAndComparison(StringComparer comparer, StringComparison comparison)
        {
            if (comparer == null) throw new ArgumentNullException(nameof(comparer));
            Comparer = comparer;
            Comparison = comparison;
        }
    }
    public sealed class CurrentCulture : StringComparerAndComparison
    {
        public CurrentCulture() : base(StringComparer.CurrentCulture, StringComparison.CurrentCulture) { }
    }
    public sealed class CurrentCultureIgnoreCase : StringComparerAndComparison
    {
        public CurrentCultureIgnoreCase() : base(StringComparer.CurrentCultureIgnoreCase, StringComparison.CurrentCultureIgnoreCase) { }
    }
    public sealed class InvariantCulture : StringComparerAndComparison
    {
        public InvariantCulture() : base(StringComparer.InvariantCulture, StringComparison.InvariantCulture) { }
    }
    public sealed class InvariantCultureIgnoreCase : StringComparerAndComparison
    {
        public InvariantCultureIgnoreCase() : base(StringComparer.InvariantCultureIgnoreCase, StringComparison.InvariantCultureIgnoreCase) { }
    }
    public sealed class Ordinal : StringComparerAndComparison
    {
        public Ordinal() : base(StringComparer.Ordinal, StringComparison.Ordinal) { }
    }
    public sealed class OrdinalIgnoreCase : StringComparerAndComparison
    {
        public OrdinalIgnoreCase() : base(StringComparer.OrdinalIgnoreCase, StringComparison.OrdinalIgnoreCase) { }
    }
}

最新更新