从具有尾随垃圾的字符串中解析整数
我需要解析出现在字符串开头的十进制整数。
十进制数后面可能有尾随垃圾。 这需要被忽略(即使它包含其他数字。)
例如
"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.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)
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