Parse an integer from a string with trailing garbage
我需要解析一个出现在字符串开头的十进制整数。
小数后面可能有尾随的垃圾。这需要被忽略(即使它包含其他数字)。
例如
1 2 3 4 | "1" => 1 " 42" => 42 " 3 -.X.-" => 3 " 2 3 4 5" => 2 |
.NET框架中是否有内置方法来执行此操作?
实现这一点很容易,但是如果标准方法存在的话,我更愿意使用它。
您可以使用LINQ来执行此操作,不需要正则表达式:
1 2 3 4 | public static int GetLeadingInt(string input) { return Int32.Parse(new string(input.Trim().TakeWhile(c => char.IsDigit(c) || c == '.').ToArray())); } |
这适用于您提供的所有示例:
1 2 3 4 5 6 7 8 9 10 11 | string[] tests = new string[] { "1", " 42", " 3 -.X.-", " 2 3 4 5" }; foreach (string test in tests) { Console.WriteLine("Result:" + GetLeadingInt(test)); } |
1 2 3 4 | foreach (var m in Regex.Matches(" 3 - .x. 4", @"\d+")) { Console.WriteLine(m); } |
按评论更新
不知道你为什么不喜欢正则表达式,所以我只会发布我认为最短的解决方案。
要获取第一个int:
1 2 3 | Match match = Regex.Match(" 3 - .x. - 4", @"\d+"); if (match.Success) Console.WriteLine(int.Parse(match.Value)); |
没有标准的.NET方法可以做到这一点,尽管我不会惊讶地发现vb在microsoft.visualBasic程序集中有一些东西(与.NET一起提供,因此即使从C使用它也不是问题)。
结果是否总是非负的(这会使事情变得更容易)?
说实话,正则表达式是这里最简单的选择,但是…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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); } |
然后,您只需要根据
我喜欢吃甜甜圈。
不过,我想补充一点,
三个示例实现:
要删除尾随的非数字字符:
1 2 3 |
要删除前导非数字字符:
1 2 3 |
要删除所有非数字字符:
1 2 3 |
当然还有:
这并不能真正回答您的问题(关于内置C方法),但您可以尝试逐个切掉输入字符串末尾的字符,直到
1 2 3 4 5 6 7 | 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); |
当然,如果
附录(2016年3月)
这可以通过在尝试每次分析之前切掉右侧所有非数字/非空格字符来更快地实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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); |
这就是我在Java中所做的事情:
1 2 3 4 5 6 | int parseLeadingInt(String input) { NumberFormat fmt = NumberFormat.getIntegerInstance(); fmt.setGroupingUsed(false); return fmt.parse(input, new ParsePosition(0)).intValue(); } |
我希望在.NET中也能实现类似的功能。
这是我当前使用的基于regex的解决方案:
1 2 3 4 5 6 7 8 9 10 | 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; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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"); |
也可以加我的。
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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()); |
消息框只是为了测试的目的,只要验证方法是否有效,就删除它。
我不知道你为什么会在这种情况下避免Regex。
这里有一个小黑客,你可以适应你的需要。
"3-.x.-".tochararray().findinteger().tolist().foreach(console.writeline);
1 2 3 4 5 6 7 8 9 10 11 | 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; } } } |
编辑:对于不正确的结果(以及维护开发人员:)是这样的。
修订如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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); } |
1 2 3 4 5 6 7 8 9 | 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); } |