从具有尾随垃圾的字符串中解析整数

我需要解析出现在字符串开头的十进制整数。

十进制数后面可能有尾随垃圾。 这需要被忽略(即使它包含其他数字。)

例如

"1" => 1 " 42 " => 42 " 3 -.X.-" => 3 " 2 3 4 5" => 2 

.NET框架中是否有内置方法来执行此操作?

int.TryParse()不合适。 它允许尾随空格但不允许其他尾随字符。

实现它很容易,但如果它存在,我宁愿使用标准方法。

 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)); 

您可以使用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)); } 

这样做没有标准的.NET方法 – 虽然我不会惊讶地发现VB在Microsoft.VisualBasic程序集中有一些东西(随.NET一起提供,所以即使从C#中使用它也不是问题)。

结果总是非负的(这会使事情变得更容易)吗?

说实话,正则表达式是最简单的选择,但……

 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 )。

我喜欢@ Donut的方法。

我想补充一点, char.IsDigitchar.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)

 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's it - get out. } if (int.TryParse(collectedNumber, out i)) Console.WriteLine(i); else Console.WriteLine("no number found"); 

这就是我在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; } 

这并没有真正回答你的问题(关于内置的C#方法),但你可以尝试逐个int.TryParse()输入字符串末尾的字符,直到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年3月)

在尝试每个解析之前,通过切断右侧的所有非数字/非空格字符可以更快地做到这一点:

 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); 

也可以加我的。

  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()); 

消息框仅用于测试目的,只需在validation方法有效后将其删除即可。

我不确定为什么你会在这种情况下避免使用正则表达式。

这是一个有点hackery,你可以根据自己的需求进行调整。

“3 -.X .-”。ToCharArray()。FindInteger()。ToList()。ForEach(Console.WriteLine);

 public static class CharArrayExtensions { public static IEnumerable FindInteger(this IEnumerable array) { foreach (var c in array) { if(char.IsNumber(c)) yield return c; } } } 

编辑:这是错误的结果(和维护开发:))。

这是一个修订:

  public static int FindFirstInteger(this IEnumerable array) { bool foundInteger = false; var ints = new List(); 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); } 
  private string GetInt(string s) { int i = 0; s = s.Trim(); while (i