Relax C#LINQ字符串比较(Trim,不区分大小写,??)

本文关键字:不区 大小写 Trim C#LINQ 字符串 比较 Relax | 更新日期: 2023-09-27 18:24:32

问题

背景故事:我正在将遗留系统的所有SQL查询重写为LINQ。

数据库并不像我预期的那样干净。这些SQL记录中有许多包含空格或视为相同的不同事例。

SELECT * 
FROM fruit 
WHERE name = @fruitname;

如果@fruitnameapple,则此查询将匹配以apple_appleAPPLE_(其中_是空白字符)结尾的任何记录。

然而,这是我的用例中预期的行为。

另一方面,LINQ字符串比较更精确。这让我很恼火,因为这样的问题不断出现在我面前。

设置

FruitTableAdapter fruitsAdapter = new FruitTableAdapter();
MyGardenDataSet.FruitDataTable fruitsTable = fruitsAdapter.GetData();

方法

// Issue 1: Does not match, '_apple' or 'APPLE_'
var fruits1 = fruitsTable.Where(row=>row.name == fruitname);
// Issue 2: String Comparison with case insensitive (does not match 'APPLE')
var fruits2 = fruitsTable.Where(
    row=>row.nameEquals(fruitname, StringComparison.OrdinalIgnoreCase));
// Issue 3: Trailing space with case insensitive
var fruits2 = fruitsTable.Where(
    row=>row.name.Trim().Equals(fruitname.Trim(), 
                                StringComparison.OrdinalIgnoreCase));

我不确定,但SQL查询和字符串比较可能有很多不同的问题。

是否有任何SQL感知StringComparison?如何在LINQ中实现与SQL相同的字符串比较?

Relax C#LINQ字符串比较(Trim,不区分大小写,??)

这里有一个很好的字符串扩展方法,它建立在关于外壳StackOverflow 的类似问题的解决方案之上

请记住,我们希望在修剪场景中允许NULL字符串,因此此扩展将在检查空值后对修剪的字符串进行不区分大小写的比较

public static class StringExtension
{
    // Trim strings and compare values without casing
    public static bool SqlCompare(this string source, string value)
    {
        // Handle nulls before trimming
        if (!string.IsNullOrEmpty(source))
            source = source.Trim();
        if (!string.IsNullOrEmpty(value))
            value = value.Trim();
        // Compare strings (case insensitive)
        return string.Equals(source, value, StringComparison.CurrentCultureIgnoreCase);
    }
}

以下是如何在LINQ语句中使用扩展:

(SysUserDisplayFavorites表由char()字段组成,这些字段的结果用空格填充。这些将被修剪并与displayFavorite对象中用户提供的值进行比较(不区分大小写)

                    var defaultFavorite = _context.SysUserDisplayFavorites
                    .Where(x => x.UserId.SqlCompare(displayFavorite.UserId))
                    .Where(x => x.ModuleCode.SqlCompare(displayFavorite.ModuleCode))
                    .Where(x => x.ActivityCode.SqlCompare(displayFavorite.ActivityCode))
                    .Where(x => x.ActivityItemCode.SqlCompare(displayFavorite.ActivityItemCode))
                    .Where(x => x.IsDefault);

这是一个非常晚的答案。

你可以使用Regex来解决你的问题以下是我尝试过的,希望它能帮助

我创建了一个示例类

 public class SampleTable
 {
     public string Name { get; set; }
     public SampleTable(string name)
     {
        Name = name;
     }
 }

填充样本数据

List<SampleTable> sampleTblList = new List<SampleTable>();
sampleTblList.Add(new SampleTable(" Apple"));
sampleTblList.Add(new SampleTable(" APPLE"));
sampleTblList.Add(new SampleTable("Apple"));
sampleTblList.Add(new SampleTable("apple"));
sampleTblList.Add(new SampleTable("apple "));
sampleTblList.Add(new SampleTable("apmangple"));

解决方案:-

string fruitName = "apple";
List<SampleTable> sortedSampleTblList = sampleTblList.Where(x => 
Regex.IsMatch(fruitName, x.Name, RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase)).ToList();

输出:-

string ans = String.Join(",", sortedSampleTblList.Select(x => x.Name.Replace(" ","_")).ToArray());
Console.Write(ans);

_Apple,_APPLE,Apple,apple,apple_

fruitsTable.Where(row => row.name.Trim().Equals(fruitname, StringComparison.OrdinalIgnoreCase));应该满足您的需要,但我很困惑,因为您在Issue 3中列出了几乎相同的内容。你是否因为重复使用fruits2而没有意识到它是有效的?

这个小NUnit测试正在通过

[Test]
public void FruitTest()
{
    var fruitsTable = new List<string> { " Apple", " APPLE", "Apple", "apple", "apple ", " apple", "APPLE " };
    var fruitname = "apple ".Trim();
    var fruits = fruitsTable.Where(row => row.Trim().Equals(fruitname, StringComparison.OrdinalIgnoreCase));
    Assert.AreEqual(fruitsTable.Count(), fruits.Count());
}