Разбирайте целое число из строки с конечным мусором
Мне нужно проанализировать десятичное целое, которое появляется в начале строки.
После десятичного числа может существовать конечный мусор. Это нужно игнорировать (даже если оно содержит другие числа.)
например.
"1" => 1
" 42 " => 42
" 3 -.X.-" => 3
" 2 3 4 5" => 2
Есть ли встроенный метод в .NET framework для этого?
int.TryParse()
не подходит. Он позволяет использовать конечные пробелы, но не другие конечные символы.
Было бы довольно легко реализовать это, но я бы предпочел использовать стандартный метод, если он существует.
Ответы
Ответ 1
foreach (var m in Regex.Matches(" 3 - .x. 4", @"\d+"))
{
Console.WriteLine(m);
}
Обновлено для комментариев
Не уверен, почему вам не нравятся регулярные выражения, поэтому я просто опубликую то, что, по моему мнению, является самым коротким решением.
Чтобы получить первый int:
Match match = Regex.Match(" 3 - .x. - 4", @"\d+");
if (match.Success)
Console.WriteLine(int.Parse(match.Value));
Ответ 2
Вы можете использовать Linq для этого, никаких регулярных выражений не требуется:
public static int GetLeadingInt(string input)
{
return Int32.Parse(new string(input.Trim().TakeWhile(c => char.IsDigit(c) || c == '.').ToArray()));
}
Это работает для всех ваших приведенных примеров:
string[] tests = new string[] {
"1",
" 42 ",
" 3 -.X.-",
" 2 3 4 5"
};
foreach (string test in tests)
{
Console.WriteLine("Result: " + GetLeadingInt(test));
}
Ответ 3
Нет стандартного метода .NET для этого - хотя я бы не удивился, обнаружив, что у VB есть что-то в сборке Microsoft.VisualBasic(которая поставляется с .NET, поэтому не стоит использовать ее даже из С#).
Будет ли результат всегда неотрицательным (что облегчит задачу)?
Честно говоря, регулярные выражения - это самый простой вариант, но...
public static string RemoveCruftFromNumber(string text)
{
int end = 0;
// First move past leading spaces
while (end < text.Length && text[end] == ' ')
{
end++;
}
// Now move past digits
while (end < text.Length && char.IsDigit(text[end]))
{
end++;
}
return text.Substring(0, end);
}
Тогда вам просто нужно вызвать int.TryParse
в результате RemoveCruftFromNumber
(не забывайте, что целое число может быть слишком большим для хранения в int
).
Ответ 4
Мне нравится подход @Donut.
Я хотел бы добавить, что char.IsDigit
и char.IsNumber
также позволяют использовать некоторые символы Unicode, которые являются цифрами на других языках и скриптах (см. здесь).
Если вы хотите проверить только цифры от 0 до 9, вы можете использовать "0123456789".Contains(c)
.
Три примера реализации:
Чтобы удалить конечные незнаковые символы:
var digits = new string(input.Trim().TakeWhile(c =>
("0123456789").Contains(c)
).ToArray());
Чтобы удалить ведущие нецифровые символы:
var digits = new string(input.Trim().SkipWhile(c =>
!("0123456789").Contains(c)
).ToArray());
Чтобы удалить все нецифровые символы:
var digits = new string(input.Trim().Where(c =>
("0123456789").Contains(c)
).ToArray());
И, конечно же: int.Parse(digits)
или int.TryParse(digits, out output)
Ответ 5
Вот как бы я это сделал в Java:
int parseLeadingInt(String input)
{
NumberFormat fmt = NumberFormat.getIntegerInstance();
fmt.setGroupingUsed(false);
return fmt.parse(input, new ParsePosition(0)).intValue();
}
Я надеялся, что в .NET возможно что-то подобное.
Это решение на основе регулярных выражений, которое я использую в настоящее время:
int? parseLeadingInt(string input)
{
int result = 0;
Match match = Regex.Match(input, "^[ \t]*\\d+");
if (match.Success && int.TryParse(match.Value, out result))
{
return result;
}
return null;
}
Ответ 6
Это не отвечает на ваш вопрос (о встроенном методе С#), но вы можете попытаться прерывать символы в конце строки ввода один за другим, пока int.TryParse()
не примет его как действительный номер:
for (int p = input.Length; p > 0; p--)
{
int num;
if (int.TryParse(input.Substring(0, p), out num))
return num;
}
throw new Exception("Malformed integer: " + input);
Конечно, это будет медленным, если input
очень длинный.
ДОБАВЛЕНИЕ (март 2016 года)
Это можно сделать быстрее, прервав все символы без цифр и не пробелов справа перед попыткой каждого разбора:
for (int p = input.Length; p > 0; p--)
{
char ch;
do
{
ch = input[--p];
} while ((ch < '0' || ch > '9') && ch != ' ' && p > 0);
p++;
int num;
if (int.TryParse(input.Substring(0, p), out num))
return num;
}
throw new Exception("Malformed integer: " + input);
Ответ 7
string s = " 3 -.X.-".Trim();
string collectedNumber = string.empty;
int i;
for (x = 0; x < s.length; x++)
{
if (int.TryParse(s[x], out i))
collectedNumber += s[x];
else
break; // not a number - that it - get out.
}
if (int.TryParse(collectedNumber, out i))
Console.WriteLine(i);
else
Console.WriteLine("no number found");
Ответ 8
Я не уверен, почему вы избежали Regex в этой ситуации.
Здесь немного хакеров, которые вы можете приспособить к вашим потребностям.
"3-.X.-". ToCharArray(). FindInteger(). ToList(). ForEach (Console.WriteLine);
public static class CharArrayExtensions
{
public static IEnumerable<char> FindInteger(this IEnumerable<char> array)
{
foreach (var c in array)
{
if(char.IsNumber(c))
yield return c;
}
}
}
EDIT:
Это верно в отношении неправильного результата (и обслуживания dev:)).
Здесь находится ревизия:
public static int FindFirstInteger(this IEnumerable<char> array)
{
bool foundInteger = false;
var ints = new List<char>();
foreach (var c in array)
{
if(char.IsNumber(c))
{
foundInteger = true;
ints.Add(c);
}
else
{
if(foundInteger)
{
break;
}
}
}
string s = string.Empty;
ints.ForEach(i => s += i.ToString());
return int.Parse(s);
}
Ответ 9
Мог бы также добавить мой тоже.
string temp = " 3 .x£";
string numbersOnly = String.Empty;
int tempInt;
for (int i = 0; i < temp.Length; i++)
{
if (Int32.TryParse(Convert.ToString(temp[i]), out tempInt))
{
numbersOnly += temp[i];
}
}
Int32.TryParse(numbersOnly, out tempInt);
MessageBox.Show(tempInt.ToString());
Поле сообщения предназначено только для тестирования, просто удалите его, как только вы подтвердите, что этот метод работает.
Ответ 10
private string GetInt(string s)
{
int i = 0;
s = s.Trim();
while (i<s.Length && char.IsDigit(s[i])) i++;
return s.Substring(0, i);
}