TitleCase方法调用Remove时触发ArgumentOutOfRangeException的原因咨询
问题场景
要实现将给定标题转为标题大小写(每个单词首字母大写、其余字符小写),当前C#实现代码如下:
public static string TitleCase(string title, string minorWords="") { title = title.ToLower(); int[] indexes = new int[title.Length]; indexes = Indexes(title); foreach(int i in indexes) { string sChar = new string(title[i].ToString()); title = title.Remove(title[i], 1); title = title.Insert(i, sChar.ToUpper()); } return title; }
执行到title.Remove(title[i], 1);语句时,抛出以下错误:
System.ArgumentOutOfRangeException : count ('1') must be less than or equal to '-83'. (Parameter 'count') Actual value was 1.
堆栈跟踪信息:
at System.ArgumentOutOfRangeException.ThrowGreater[T](T value, T other, String paramName) at System.String.Remove(Int32 startIndex, Int32 count) at Kata.TitleCase(String title, String minorWords)
at Solution.SolutionTest.MyTest(String sampleTitle, String sampleMinorWords, String expected) at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
错误原因
核心问题是**String.Remove方法的参数传错了**:
String.Remove(int startIndex, int count)的第一个参数要求是要删除字符的起始索引位置(整数),但你传入的title[i]是字符串中索引i处的字符本身,当这个字符被隐式转换为int时,得到的是它的ASCII/Unicode编码值(比如小写字母'a'对应97,某些特殊字符可能对应负数),而非你需要的索引位置i。- 这个错误的参数导致
startIndex值远超出字符串的有效索引范围,进而触发ArgumentOutOfRangeException,错误信息里的奇怪数值(比如-83)就是字符编码转换后的结果。
解决方法
1. 修正Remove方法的参数
将title.Remove(title[i], 1)改为title.Remove(i, 1),传入正确的索引位置i:
public static string TitleCase(string title, string minorWords="") { if (string.IsNullOrEmpty(title)) return title; title = title.ToLower(); int[] indexes = Indexes(title); foreach(int i in indexes) { char upperChar = char.ToUpper(title[i]); title = title.Remove(i, 1).Insert(i, upperChar.ToString()); } return title; }
2. 更高效的实现方式(推荐)
由于C#中字符串是不可变类型,多次调用Remove和Insert会生成多个字符串实例,效率较低。建议转为char数组操作,修改完成后再转回字符串:
public static string TitleCase(string title, string minorWords = "") { if (string.IsNullOrEmpty(title)) return title; char[] titleChars = title.ToLower().ToCharArray(); int[] indexes = Indexes(title); foreach (int i in indexes) { // 增加边界检查,避免索引越界 if (i >= 0 && i < titleChars.Length) { titleChars[i] = char.ToUpper(titleChars[i]); } } return new string(titleChars); }
3. 额外注意事项
- 确保
Indexes方法返回的索引值都在有效范围内(0到字符串长度-1之间),否则即使修正了参数,仍可能触发索引越界错误。 - 如果需要处理
minorWords(排除小词的首字母大写),还需在Indexes方法中加入对应逻辑,过滤掉小词的首字母索引。
内容的提问来源于stack exchange,提问作者Jaret Sanchez

