Я сравниваю обновления с двумя строками. я сделал:
string1 != string2
и они оказываются разными. Я помещал их в "Добавить часы", и я вижу, что единственное различие заключается в том, что у одного есть разрывы строк, а у другого нет.:
string1 = "This is a test. \nThis is a test";
string2 = "This is a test. This is a test";
В основном я хочу сделать сравнение, но не включаю разрывы строк. Поэтому, если разрывы строк - это единственная разница, тогда считайте их равными.
Быстрый и грязный способ, когда производительность не является большой проблемой:
string1.Replace("\n", "") != string2.Replace("\n", "")
\r
.
Предполагая, что:
"\n"
пустой строкой слишком неэффективной.Тогда:
public bool LinelessEquals(string x, string y)
{
//deal with quickly handlable cases quickly.
if(ReferenceEquals(x, y))//same instance
return true; // - generally happens often in real code,
//and is a fast check, so always worth doing first.
//We already know they aren't both null as
//ReferenceEquals(null, null) returns true.
if(x == null || y == null)
return false;
IEnumerator<char> eX = x.Where(c => c != '\n').GetEnumerator();
IEnumerator<char> eY = y.Where(c => c != '\n').GetEnumerator();
while(eX.MoveNext())
{
if(!eY.MoveNext()) //y is shorter
return false;
if(ex.Current != ey.Current)
return false;
}
return !ey.MoveNext(); //check if y was longer.
}
Это определяется как равенство, а не неравенство, поэтому вы можете легко адаптировать его как реализацию IEqualityComparer<string>.Equals
. Ваш вопрос для linebreak-less string1 != string2
будет выглядеть следующим образом: !LinelessEquals(string1, string2)
Я предлагаю регулярное выражение для сокращения всех space
, tab
, \r
, \n
до одного пробела:
Regex.Replace(string1, @"\s+", " ") != Regex.Replace(string2, @"\s+", " ")
Здесь сопоставляет равенство для строк, которые игнорируют определенные символы, такие как \r
и \n
.
Эта реализация не выделяет кучную память во время выполнения, что помогает ее производительности. Он также позволяет избежать виртуальных вызовов через IEnumerable
и IEnumerator
.
public sealed class SelectiveStringComparer : IEqualityComparer<string>
{
private readonly string _ignoreChars;
public SelectiveStringComparer(string ignoreChars = "\r\n")
{
_ignoreChars = ignoreChars;
}
public bool Equals(string x, string y)
{
if (ReferenceEquals(x, y))
return true;
if (x == null || y == null)
return false;
var ix = 0;
var iy = 0;
while (true)
{
while (ix < x.Length && _ignoreChars.IndexOf(x[ix]) != -1)
ix++;
while (iy < y.Length && _ignoreChars.IndexOf(y[iy]) != -1)
iy++;
if (ix >= x.Length)
return iy >= y.Length;
if (iy >= y.Length)
return false;
if (x[ix] != y[iy])
return false;
ix++;
iy++;
}
}
public int GetHashCode(string obj)
{
throw new NotSupportedException();
}
}
Более чистый подход заключается в использовании:
string1.Replace(Environment.NewLine, String.Empty) != string2.Replace(Environment.NewLine, String.Empty);
Здесь версия в VB.net на основе Drew Noakes отвечает
Dim g_sIgnore As String = vbSpace & vbNewLine & vbTab 'String.Format("\n\r\t ")
Public Function StringCompareIgnoringWhitespace(s1 As String, s2 As String) As Boolean
Dim i1 As Integer = 0
Dim i2 As Integer = 0
Dim s1l As Integer = s1.Length
Dim s2l As Integer = s2.Length
Do
While i1 < s1l AndAlso g_sIgnore.IndexOf(s1(i1)) <> -1
i1 += 1
End While
While i2 < s2l AndAlso g_sIgnore.IndexOf(s2(i2)) <> -1
i2 += 1
End While
If i1 = s1l And i2 = s2l Then
Return True
Else
If i1 < s1l AndAlso i2 < s2l AndAlso s1(i1) = s2(i2) Then
i1 += 1
i2 += 1
Else
Return False
End If
End If
Loop
Return False
End Function
Я также тестировал его с помощью
Try
Debug.Assert(Not StringCompareIgnoringWhitespace("a", "z"))
Debug.Assert(Not StringCompareIgnoringWhitespace("aa", "zz"))
Debug.Assert(StringCompareIgnoringWhitespace("", ""))
Debug.Assert(StringCompareIgnoringWhitespace(" ", ""))
Debug.Assert(StringCompareIgnoringWhitespace("", " "))
Debug.Assert(StringCompareIgnoringWhitespace(" a", "a "))
Debug.Assert(StringCompareIgnoringWhitespace(" aa", "aa "))
Debug.Assert(StringCompareIgnoringWhitespace(" aa ", " aa "))
Debug.Assert(StringCompareIgnoringWhitespace(" aa a", " aa a"))
Debug.Assert(Not StringCompareIgnoringWhitespace("a", ""))
Debug.Assert(Not StringCompareIgnoringWhitespace("", "a"))
Debug.Assert(Not StringCompareIgnoringWhitespace("ccc", ""))
Debug.Assert(Not StringCompareIgnoringWhitespace("", "ccc"))
Catch ex As Exception
Console.WriteLine(ex.ToString)
End Try
Это обобщенная и проверенная версия ответа Джона Ханнаса.
/// <summary>
/// Compares two character enumerables one character at a time, ignoring those specified.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="ignoreThese"> If not specified, the default is to ignore linefeed and newline: {'\r', '\n'} </param>
/// <returns></returns>
public static bool EqualsIgnoreSome(this IEnumerable<char> x, IEnumerable<char> y, params char[] ignoreThese)
{
// First deal with quickly handlable cases quickly:
// Same instance - generally happens often in real code, and is a fast check, so always worth doing first.
if (ReferenceEquals(x, y))
return true; //
// We already know they aren't both null as ReferenceEquals(null, null) returns true.
if (x == null || y == null)
return false;
// Default ignore is newlines:
if (ignoreThese == null || ignoreThese.Length == 0)
ignoreThese = new char[] { '\r', '\n' };
// Filters by specifying enumerator.
IEnumerator<char> eX = x.Where(c => !ignoreThese.Contains(c)).GetEnumerator();
IEnumerator<char> eY = y.Where(c => !ignoreThese.Contains(c)).GetEnumerator();
// Compares.
while (eX.MoveNext())
{
if (!eY.MoveNext()) //y is shorter
return false;
if (eX.Current != eY.Current)
return false;
}
return !eY.MoveNext(); //check if y was longer.
}
string1.replace('\n','') != string2.replace('\n','')
Не могли бы вы просто разбить разрывы строк перед сравнением строк?
например. (Псевдокод)...
string1.replace('\n','') != string2.replace('\n','')