C# - How to sort strings that include text and numbers
up vote
0
down vote
favorite
I have a listview that is filled with computernames and usernames and a number(as string). I already created my own ListViewItemComparer using the IComparer interface. But it doesn´t sort the items correctly like how I want.
This is how it should sort the computers for example:
Computer-1
Computer-2
Computer-3
...
Computer-15
and this is how it sorts them:
Computer-1
Computer-10
Computer-11
...
Computer-2
Computer-3
The problem is that i can´t simply cut the "computer-" part out and compare the numbers that follows as this was just an example and the computernames can be everything(aaa393bbb333, ccccvvvv, 222hhhdh,Computer-01, Computer-02,....)
This is my code:
private bool isNumeric(String pInput)
int o;
return int.TryParse(pInput, out o);
public int Compare(object x, object y)
ListViewItem itemX = x as ListViewItem;
ListViewItem itemY = y as ListViewItem;
//
int returnVal = -1;
if (itemX == null && itemY == null) returnVal = 0;
else if (itemX == null) returnVal = -1;
else if (itemY == null) returnVal = 1;
else if (itemX.SubItems.Count - 1 < col && itemY.SubItems.Count - 1 < col) returnVal = 0;
else if (itemX.SubItems.Count - 1 < col) returnVal = -1;
else if (itemY.SubItems.Count - 1 < col) returnVal = 1;
else if(isNumeric(itemX.SubItems[col].Text) && isNumeric(itemY.SubItems[col].Text))
//used for number comparison
int value1 = int.Parse(itemX.SubItems[col].Text);
int value2 = int.Parse(itemY.SubItems[col].Text);
if (value1 == value2) returnVal = 0;
else if (value1 < value2) returnVal = -1;
else if (value1 > value2) returnVal = 1;
else returnVal = String.Compare(itemX.SubItems[col].Text, itemY.SubItems[col].Text);
if (order == SortOrder.Descending)
returnVal *= -1;
return returnVal;
c# sorting compare string-comparison compareto
add a comment |
up vote
0
down vote
favorite
I have a listview that is filled with computernames and usernames and a number(as string). I already created my own ListViewItemComparer using the IComparer interface. But it doesn´t sort the items correctly like how I want.
This is how it should sort the computers for example:
Computer-1
Computer-2
Computer-3
...
Computer-15
and this is how it sorts them:
Computer-1
Computer-10
Computer-11
...
Computer-2
Computer-3
The problem is that i can´t simply cut the "computer-" part out and compare the numbers that follows as this was just an example and the computernames can be everything(aaa393bbb333, ccccvvvv, 222hhhdh,Computer-01, Computer-02,....)
This is my code:
private bool isNumeric(String pInput)
int o;
return int.TryParse(pInput, out o);
public int Compare(object x, object y)
ListViewItem itemX = x as ListViewItem;
ListViewItem itemY = y as ListViewItem;
//
int returnVal = -1;
if (itemX == null && itemY == null) returnVal = 0;
else if (itemX == null) returnVal = -1;
else if (itemY == null) returnVal = 1;
else if (itemX.SubItems.Count - 1 < col && itemY.SubItems.Count - 1 < col) returnVal = 0;
else if (itemX.SubItems.Count - 1 < col) returnVal = -1;
else if (itemY.SubItems.Count - 1 < col) returnVal = 1;
else if(isNumeric(itemX.SubItems[col].Text) && isNumeric(itemY.SubItems[col].Text))
//used for number comparison
int value1 = int.Parse(itemX.SubItems[col].Text);
int value2 = int.Parse(itemY.SubItems[col].Text);
if (value1 == value2) returnVal = 0;
else if (value1 < value2) returnVal = -1;
else if (value1 > value2) returnVal = 1;
else returnVal = String.Compare(itemX.SubItems[col].Text, itemY.SubItems[col].Text);
if (order == SortOrder.Descending)
returnVal *= -1;
return returnVal;
c# sorting compare string-comparison compareto
Of course you can "cut out" the computer name from the number, just don't forget about them ;-) When comparing two computer names, you first compare the computer name part without the number. If they are different (unequal), then you got the desired comparison result now. If the computer name parts are identical (equal), you will then compare the number parts. So, now you also got the desired comparision result even if the computer name parts where the same...
– elgonzo
Nov 10 at 15:54
2
There is a "natural sort" method built into windows. File explorer uses it to sort alpha numeric file names
– Disaffected 1070452
Nov 10 at 15:59
Thanks for your answer. But you didn´t understand me. "Computer-" was only an example of a computername. The computer names can be everything. So a computername can even be this aaaa100aa2. But how would i compare that to other computernames?
– C.M.
Nov 10 at 16:00
@Disaffected 1070452 yes this is exactly what i am looking for. But how do i implement that?
– C.M.
Nov 10 at 16:05
Go to your favorite search engine and research "natural sort" There are dozens of solutions already here
– Disaffected 1070452
Nov 10 at 16:10
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I have a listview that is filled with computernames and usernames and a number(as string). I already created my own ListViewItemComparer using the IComparer interface. But it doesn´t sort the items correctly like how I want.
This is how it should sort the computers for example:
Computer-1
Computer-2
Computer-3
...
Computer-15
and this is how it sorts them:
Computer-1
Computer-10
Computer-11
...
Computer-2
Computer-3
The problem is that i can´t simply cut the "computer-" part out and compare the numbers that follows as this was just an example and the computernames can be everything(aaa393bbb333, ccccvvvv, 222hhhdh,Computer-01, Computer-02,....)
This is my code:
private bool isNumeric(String pInput)
int o;
return int.TryParse(pInput, out o);
public int Compare(object x, object y)
ListViewItem itemX = x as ListViewItem;
ListViewItem itemY = y as ListViewItem;
//
int returnVal = -1;
if (itemX == null && itemY == null) returnVal = 0;
else if (itemX == null) returnVal = -1;
else if (itemY == null) returnVal = 1;
else if (itemX.SubItems.Count - 1 < col && itemY.SubItems.Count - 1 < col) returnVal = 0;
else if (itemX.SubItems.Count - 1 < col) returnVal = -1;
else if (itemY.SubItems.Count - 1 < col) returnVal = 1;
else if(isNumeric(itemX.SubItems[col].Text) && isNumeric(itemY.SubItems[col].Text))
//used for number comparison
int value1 = int.Parse(itemX.SubItems[col].Text);
int value2 = int.Parse(itemY.SubItems[col].Text);
if (value1 == value2) returnVal = 0;
else if (value1 < value2) returnVal = -1;
else if (value1 > value2) returnVal = 1;
else returnVal = String.Compare(itemX.SubItems[col].Text, itemY.SubItems[col].Text);
if (order == SortOrder.Descending)
returnVal *= -1;
return returnVal;
c# sorting compare string-comparison compareto
I have a listview that is filled with computernames and usernames and a number(as string). I already created my own ListViewItemComparer using the IComparer interface. But it doesn´t sort the items correctly like how I want.
This is how it should sort the computers for example:
Computer-1
Computer-2
Computer-3
...
Computer-15
and this is how it sorts them:
Computer-1
Computer-10
Computer-11
...
Computer-2
Computer-3
The problem is that i can´t simply cut the "computer-" part out and compare the numbers that follows as this was just an example and the computernames can be everything(aaa393bbb333, ccccvvvv, 222hhhdh,Computer-01, Computer-02,....)
This is my code:
private bool isNumeric(String pInput)
int o;
return int.TryParse(pInput, out o);
public int Compare(object x, object y)
ListViewItem itemX = x as ListViewItem;
ListViewItem itemY = y as ListViewItem;
//
int returnVal = -1;
if (itemX == null && itemY == null) returnVal = 0;
else if (itemX == null) returnVal = -1;
else if (itemY == null) returnVal = 1;
else if (itemX.SubItems.Count - 1 < col && itemY.SubItems.Count - 1 < col) returnVal = 0;
else if (itemX.SubItems.Count - 1 < col) returnVal = -1;
else if (itemY.SubItems.Count - 1 < col) returnVal = 1;
else if(isNumeric(itemX.SubItems[col].Text) && isNumeric(itemY.SubItems[col].Text))
//used for number comparison
int value1 = int.Parse(itemX.SubItems[col].Text);
int value2 = int.Parse(itemY.SubItems[col].Text);
if (value1 == value2) returnVal = 0;
else if (value1 < value2) returnVal = -1;
else if (value1 > value2) returnVal = 1;
else returnVal = String.Compare(itemX.SubItems[col].Text, itemY.SubItems[col].Text);
if (order == SortOrder.Descending)
returnVal *= -1;
return returnVal;
c# sorting compare string-comparison compareto
c# sorting compare string-comparison compareto
edited Nov 10 at 16:01
asked Nov 10 at 15:46
C.M.
65
65
Of course you can "cut out" the computer name from the number, just don't forget about them ;-) When comparing two computer names, you first compare the computer name part without the number. If they are different (unequal), then you got the desired comparison result now. If the computer name parts are identical (equal), you will then compare the number parts. So, now you also got the desired comparision result even if the computer name parts where the same...
– elgonzo
Nov 10 at 15:54
2
There is a "natural sort" method built into windows. File explorer uses it to sort alpha numeric file names
– Disaffected 1070452
Nov 10 at 15:59
Thanks for your answer. But you didn´t understand me. "Computer-" was only an example of a computername. The computer names can be everything. So a computername can even be this aaaa100aa2. But how would i compare that to other computernames?
– C.M.
Nov 10 at 16:00
@Disaffected 1070452 yes this is exactly what i am looking for. But how do i implement that?
– C.M.
Nov 10 at 16:05
Go to your favorite search engine and research "natural sort" There are dozens of solutions already here
– Disaffected 1070452
Nov 10 at 16:10
add a comment |
Of course you can "cut out" the computer name from the number, just don't forget about them ;-) When comparing two computer names, you first compare the computer name part without the number. If they are different (unequal), then you got the desired comparison result now. If the computer name parts are identical (equal), you will then compare the number parts. So, now you also got the desired comparision result even if the computer name parts where the same...
– elgonzo
Nov 10 at 15:54
2
There is a "natural sort" method built into windows. File explorer uses it to sort alpha numeric file names
– Disaffected 1070452
Nov 10 at 15:59
Thanks for your answer. But you didn´t understand me. "Computer-" was only an example of a computername. The computer names can be everything. So a computername can even be this aaaa100aa2. But how would i compare that to other computernames?
– C.M.
Nov 10 at 16:00
@Disaffected 1070452 yes this is exactly what i am looking for. But how do i implement that?
– C.M.
Nov 10 at 16:05
Go to your favorite search engine and research "natural sort" There are dozens of solutions already here
– Disaffected 1070452
Nov 10 at 16:10
Of course you can "cut out" the computer name from the number, just don't forget about them ;-) When comparing two computer names, you first compare the computer name part without the number. If they are different (unequal), then you got the desired comparison result now. If the computer name parts are identical (equal), you will then compare the number parts. So, now you also got the desired comparision result even if the computer name parts where the same...
– elgonzo
Nov 10 at 15:54
Of course you can "cut out" the computer name from the number, just don't forget about them ;-) When comparing two computer names, you first compare the computer name part without the number. If they are different (unequal), then you got the desired comparison result now. If the computer name parts are identical (equal), you will then compare the number parts. So, now you also got the desired comparision result even if the computer name parts where the same...
– elgonzo
Nov 10 at 15:54
2
2
There is a "natural sort" method built into windows. File explorer uses it to sort alpha numeric file names
– Disaffected 1070452
Nov 10 at 15:59
There is a "natural sort" method built into windows. File explorer uses it to sort alpha numeric file names
– Disaffected 1070452
Nov 10 at 15:59
Thanks for your answer. But you didn´t understand me. "Computer-" was only an example of a computername. The computer names can be everything. So a computername can even be this aaaa100aa2. But how would i compare that to other computernames?
– C.M.
Nov 10 at 16:00
Thanks for your answer. But you didn´t understand me. "Computer-" was only an example of a computername. The computer names can be everything. So a computername can even be this aaaa100aa2. But how would i compare that to other computernames?
– C.M.
Nov 10 at 16:00
@Disaffected 1070452 yes this is exactly what i am looking for. But how do i implement that?
– C.M.
Nov 10 at 16:05
@Disaffected 1070452 yes this is exactly what i am looking for. But how do i implement that?
– C.M.
Nov 10 at 16:05
Go to your favorite search engine and research "natural sort" There are dozens of solutions already here
– Disaffected 1070452
Nov 10 at 16:10
Go to your favorite search engine and research "natural sort" There are dozens of solutions already here
– Disaffected 1070452
Nov 10 at 16:10
add a comment |
1 Answer
1
active
oldest
votes
up vote
0
down vote
You could use the regex expression
(?<=D)(?=d)|(?<=d)(?=D)
to split the string into numbers and text.
string parts = Regex.Split(theString, @"(?<=D)(?=d)|(?<=d)(?=D)");
This yields alternately numbers and texts. How it works:
(?<=exp)pos Match any position pos following a prefix exp.
pos(?=exp) Match any position pos preceding a suffix exp.
So the regex means, split at a position between text and number or at a position between number and text where D
stands for a non-digit character, d
for a digit character and |
for OR.
You will have to test whether the first part is a text or a number with
bool firstIsNumber = Char.IsDigit(parts[0][0]);
If the first part is a number, all parts at even indexes are numbers and all parts at odd indexes are texts and vice versa.
private static readonly Regex numTextSplitRegex =
new Regex(@"(?<=D)(?=d)|(?<=d)(?=D)", RegexOptions.Compiled);
public int Compare(string x, string y)
x = x ?? "";
y = y ?? "";
string xParts = numTextSplitRegex.Split(x);
string yParts = numTextSplitRegex.Split(y);
bool firstXIsNumber = xParts[0].Length > 0 && Char.IsDigit(xParts[0][0]);
bool firstYIsNumber = yParts[0].Length > 0 && Char.IsDigit(yParts[0][0]);
if (firstXIsNumber != firstYIsNumber)
return x.CompareTo(y);
for (int i = 0; i < Math.Min(xParts.Length, yParts.Length); i++)
int result;
if (firstXIsNumber == (i % 2 == 0)) // Compare numbers.
long a = Int64.Parse(xParts[i]);
long b = Int64.Parse(yParts[i]);
result = a.CompareTo(b);
else // Compare texts.
result = xParts[i].CompareTo(yParts[i]);
if (result != 0)
return result;
return xParts.Length.CompareTo(yParts.Length);
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
You could use the regex expression
(?<=D)(?=d)|(?<=d)(?=D)
to split the string into numbers and text.
string parts = Regex.Split(theString, @"(?<=D)(?=d)|(?<=d)(?=D)");
This yields alternately numbers and texts. How it works:
(?<=exp)pos Match any position pos following a prefix exp.
pos(?=exp) Match any position pos preceding a suffix exp.
So the regex means, split at a position between text and number or at a position between number and text where D
stands for a non-digit character, d
for a digit character and |
for OR.
You will have to test whether the first part is a text or a number with
bool firstIsNumber = Char.IsDigit(parts[0][0]);
If the first part is a number, all parts at even indexes are numbers and all parts at odd indexes are texts and vice versa.
private static readonly Regex numTextSplitRegex =
new Regex(@"(?<=D)(?=d)|(?<=d)(?=D)", RegexOptions.Compiled);
public int Compare(string x, string y)
x = x ?? "";
y = y ?? "";
string xParts = numTextSplitRegex.Split(x);
string yParts = numTextSplitRegex.Split(y);
bool firstXIsNumber = xParts[0].Length > 0 && Char.IsDigit(xParts[0][0]);
bool firstYIsNumber = yParts[0].Length > 0 && Char.IsDigit(yParts[0][0]);
if (firstXIsNumber != firstYIsNumber)
return x.CompareTo(y);
for (int i = 0; i < Math.Min(xParts.Length, yParts.Length); i++)
int result;
if (firstXIsNumber == (i % 2 == 0)) // Compare numbers.
long a = Int64.Parse(xParts[i]);
long b = Int64.Parse(yParts[i]);
result = a.CompareTo(b);
else // Compare texts.
result = xParts[i].CompareTo(yParts[i]);
if (result != 0)
return result;
return xParts.Length.CompareTo(yParts.Length);
add a comment |
up vote
0
down vote
You could use the regex expression
(?<=D)(?=d)|(?<=d)(?=D)
to split the string into numbers and text.
string parts = Regex.Split(theString, @"(?<=D)(?=d)|(?<=d)(?=D)");
This yields alternately numbers and texts. How it works:
(?<=exp)pos Match any position pos following a prefix exp.
pos(?=exp) Match any position pos preceding a suffix exp.
So the regex means, split at a position between text and number or at a position between number and text where D
stands for a non-digit character, d
for a digit character and |
for OR.
You will have to test whether the first part is a text or a number with
bool firstIsNumber = Char.IsDigit(parts[0][0]);
If the first part is a number, all parts at even indexes are numbers and all parts at odd indexes are texts and vice versa.
private static readonly Regex numTextSplitRegex =
new Regex(@"(?<=D)(?=d)|(?<=d)(?=D)", RegexOptions.Compiled);
public int Compare(string x, string y)
x = x ?? "";
y = y ?? "";
string xParts = numTextSplitRegex.Split(x);
string yParts = numTextSplitRegex.Split(y);
bool firstXIsNumber = xParts[0].Length > 0 && Char.IsDigit(xParts[0][0]);
bool firstYIsNumber = yParts[0].Length > 0 && Char.IsDigit(yParts[0][0]);
if (firstXIsNumber != firstYIsNumber)
return x.CompareTo(y);
for (int i = 0; i < Math.Min(xParts.Length, yParts.Length); i++)
int result;
if (firstXIsNumber == (i % 2 == 0)) // Compare numbers.
long a = Int64.Parse(xParts[i]);
long b = Int64.Parse(yParts[i]);
result = a.CompareTo(b);
else // Compare texts.
result = xParts[i].CompareTo(yParts[i]);
if (result != 0)
return result;
return xParts.Length.CompareTo(yParts.Length);
add a comment |
up vote
0
down vote
up vote
0
down vote
You could use the regex expression
(?<=D)(?=d)|(?<=d)(?=D)
to split the string into numbers and text.
string parts = Regex.Split(theString, @"(?<=D)(?=d)|(?<=d)(?=D)");
This yields alternately numbers and texts. How it works:
(?<=exp)pos Match any position pos following a prefix exp.
pos(?=exp) Match any position pos preceding a suffix exp.
So the regex means, split at a position between text and number or at a position between number and text where D
stands for a non-digit character, d
for a digit character and |
for OR.
You will have to test whether the first part is a text or a number with
bool firstIsNumber = Char.IsDigit(parts[0][0]);
If the first part is a number, all parts at even indexes are numbers and all parts at odd indexes are texts and vice versa.
private static readonly Regex numTextSplitRegex =
new Regex(@"(?<=D)(?=d)|(?<=d)(?=D)", RegexOptions.Compiled);
public int Compare(string x, string y)
x = x ?? "";
y = y ?? "";
string xParts = numTextSplitRegex.Split(x);
string yParts = numTextSplitRegex.Split(y);
bool firstXIsNumber = xParts[0].Length > 0 && Char.IsDigit(xParts[0][0]);
bool firstYIsNumber = yParts[0].Length > 0 && Char.IsDigit(yParts[0][0]);
if (firstXIsNumber != firstYIsNumber)
return x.CompareTo(y);
for (int i = 0; i < Math.Min(xParts.Length, yParts.Length); i++)
int result;
if (firstXIsNumber == (i % 2 == 0)) // Compare numbers.
long a = Int64.Parse(xParts[i]);
long b = Int64.Parse(yParts[i]);
result = a.CompareTo(b);
else // Compare texts.
result = xParts[i].CompareTo(yParts[i]);
if (result != 0)
return result;
return xParts.Length.CompareTo(yParts.Length);
You could use the regex expression
(?<=D)(?=d)|(?<=d)(?=D)
to split the string into numbers and text.
string parts = Regex.Split(theString, @"(?<=D)(?=d)|(?<=d)(?=D)");
This yields alternately numbers and texts. How it works:
(?<=exp)pos Match any position pos following a prefix exp.
pos(?=exp) Match any position pos preceding a suffix exp.
So the regex means, split at a position between text and number or at a position between number and text where D
stands for a non-digit character, d
for a digit character and |
for OR.
You will have to test whether the first part is a text or a number with
bool firstIsNumber = Char.IsDigit(parts[0][0]);
If the first part is a number, all parts at even indexes are numbers and all parts at odd indexes are texts and vice versa.
private static readonly Regex numTextSplitRegex =
new Regex(@"(?<=D)(?=d)|(?<=d)(?=D)", RegexOptions.Compiled);
public int Compare(string x, string y)
x = x ?? "";
y = y ?? "";
string xParts = numTextSplitRegex.Split(x);
string yParts = numTextSplitRegex.Split(y);
bool firstXIsNumber = xParts[0].Length > 0 && Char.IsDigit(xParts[0][0]);
bool firstYIsNumber = yParts[0].Length > 0 && Char.IsDigit(yParts[0][0]);
if (firstXIsNumber != firstYIsNumber)
return x.CompareTo(y);
for (int i = 0; i < Math.Min(xParts.Length, yParts.Length); i++)
int result;
if (firstXIsNumber == (i % 2 == 0)) // Compare numbers.
long a = Int64.Parse(xParts[i]);
long b = Int64.Parse(yParts[i]);
result = a.CompareTo(b);
else // Compare texts.
result = xParts[i].CompareTo(yParts[i]);
if (result != 0)
return result;
return xParts.Length.CompareTo(yParts.Length);
edited Nov 10 at 16:39
answered Nov 10 at 15:57
Olivier Jacot-Descombes
64.2k883134
64.2k883134
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53240593%2fc-sharp-how-to-sort-strings-that-include-text-and-numbers%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Of course you can "cut out" the computer name from the number, just don't forget about them ;-) When comparing two computer names, you first compare the computer name part without the number. If they are different (unequal), then you got the desired comparison result now. If the computer name parts are identical (equal), you will then compare the number parts. So, now you also got the desired comparision result even if the computer name parts where the same...
– elgonzo
Nov 10 at 15:54
2
There is a "natural sort" method built into windows. File explorer uses it to sort alpha numeric file names
– Disaffected 1070452
Nov 10 at 15:59
Thanks for your answer. But you didn´t understand me. "Computer-" was only an example of a computername. The computer names can be everything. So a computername can even be this aaaa100aa2. But how would i compare that to other computernames?
– C.M.
Nov 10 at 16:00
@Disaffected 1070452 yes this is exactly what i am looking for. But how do i implement that?
– C.M.
Nov 10 at 16:05
Go to your favorite search engine and research "natural sort" There are dozens of solutions already here
– Disaffected 1070452
Nov 10 at 16:10