我想用特定的长度变量拆分String 它需要进行边界检查,以便在字符串的最后一部分不长于或长于字符串时不爆炸。寻找最简洁(但可以理解)的版本。
示例:
string x = "AAABBBCC";
string[] arr = x.SplitByLength(3);
// arr[0] -> "AAA";
// arr[1] -> "BBB";
// arr[2] -> "CC"
答案 0 :(得分:62)
您需要使用循环:
public static IEnumerable<string> SplitByLength(this string str, int maxLength) {
for (int index = 0; index < str.Length; index += maxLength) {
yield return str.Substring(index, Math.Min(maxLength, str.Length - index));
}
}
替代:
public static IEnumerable<string> SplitByLength(this string str, int maxLength) {
int index = 0;
while(true) {
if (index + maxLength >= str.Length) {
yield return str.Substring(index);
yield break;
}
yield return str.Substring(index, maxLength);
index += maxLength;
}
}
2 nd 替代方案:(对于那些无法忍受的人while(true)
)
public static IEnumerable<string> SplitByLength(this string str, int maxLength) {
int index = 0;
while(index + maxLength < str.Length) {
yield return str.Substring(index, maxLength);
index += maxLength;
}
yield return str.Substring(index);
}
答案 1 :(得分:12)
易于理解的版本:
string x = "AAABBBCC";
List<string> a = new List<string>();
for (int i = 0; i < x.Length; i += 3)
{
if((i + 3) < x.Length)
a.Add(x.Substring(i, 3));
else
a.Add(x.Substring(i));
}
虽然最好3应该是一个不错的常量。
答案 2 :(得分:6)
它不是特别简洁,但我可能会使用这样的扩展方法:
public static IEnumerable<string> SplitByLength(this string s, int length)
{
for (int i = 0; i < s.Length; i += length)
{
if (i + length <= s.Length)
{
yield return s.Substring(i, length);
}
else
{
yield return s.Substring(i);
}
}
}
请注意,我返回IEnumerable<string>
,而不是数组。如果要将结果转换为数组,请使用ToArray
:
string[] arr = x.SplitByLength(3).ToArray();
答案 3 :(得分:4)
这就是我要做的事情:
public static IEnumerable<string> EnumerateByLength(this string text, int length) {
int index = 0;
while (index < text.Length) {
int charCount = Math.Min(length, text.Length - index);
yield return text.Substring(index, charCount);
index += length;
}
}
这个方法会提供延迟执行(这对于像string
这样的不可变类并不重要,但值得注意)。
然后,如果您想要一个方法为您填充数组,您可以:
public static string[] SplitByLength(this string text, int length) {
return text.EnumerateByLength(length).ToArray();
}
我之所以使用名称EnumerateByLength
而不是SplitByLength
作为“核心”方法的原因是string.Split
会返回string[]
,所以我认为优先对于名称以Split
开头的方法返回数组。
但那只是我。
答案 4 :(得分:3)
我的解决方案:
public static string[] SplitToChunks(this string source, int maxLength)
{
return source
.Where((x, i) => i % maxLength == 0)
.Select(
(x, i) => new string(source
.Skip(i * maxLength)
.Take(maxLength)
.ToArray()))
.ToArray();
}
我实际上宁愿使用List<string>
代替string[]
。
答案 5 :(得分:1)
public static IEnumerable<string> SplitByLength(this string str, int length)
{
return str.Batch(length, String.Concat);
}
On 3.5 Concat需要一个数组,因此我们可以将Concat
与ToArray
或new String
一起使用:
public static IEnumerable<string> SplitByLength(this string str, int length)
{
return str.Batch(length, chars => new String(chars.ToArray()));
}
将字符串视为字符集合可能有点不直观,因此可能会提供字符串操作。
答案 6 :(得分:1)
UPD:使用一些Linq使其实际上简洁
static IEnumerable EnumerateByLength(string str, int len)
{
Match m = (new Regex(string.Format("^(.{{1,{0}}})*$", len))).Match(str);
if (m.Groups.Count <= 1)
return Empty;
return (from Capture c in m.Groups[1].Captures select c.Value);
}
初始版本:
static string[] Empty = new string [] {};
static string[] SplitByLength(string str, int len)
{
Regex r = new Regex(string.Format("^(.{{1,{0}}})*$",len));
Match m = r.Match(str);
if(m.Groups.Count <= 1)
return Empty;
string [] result = new string[m.Groups[1].Captures.Count];
int ix = 0;
foreach(Capture c in m.Groups[1].Captures)
{
result[ix++] = c.Value;
}
return result;
}
答案 7 :(得分:1)
另一个轻微变体(经典但简单实用):
class Program
{
static void Main(string[] args) {
string msg = "AAABBBCC";
string[] test = msg.SplitByLength(3);
}
}
public static class SplitStringByLength
{
public static string[] SplitByLength(this string inputString, int segmentSize) {
List<string> segments = new List<string>();
int wholeSegmentCount = inputString.Length / segmentSize;
int i;
for (i = 0; i < wholeSegmentCount; i++) {
segments.Add(inputString.Substring(i * segmentSize, segmentSize));
}
if (inputString.Length % segmentSize != 0) {
segments.Add(inputString.Substring(i * segmentSize, inputString.Length - i * segmentSize));
}
return segments.ToArray();
}
}
答案 8 :(得分:0)
private string[] SplitByLength(string s, int d)
{
List<string> stringList = new List<string>();
if (s.Length <= d) stringList.Add(s);
else
{
int x = 0;
for (; (x + d) < s.Length; x += d)
{
stringList.Add(s.Substring(x, d));
}
stringList.Add(s.Substring(x));
}
return stringList.ToArray();
}
答案 9 :(得分:0)
private void button2_Click(object sender, EventArgs e)
{
string s = "AAABBBCCC";
string[] a = SplitByLenght(s,3);
}
private string[] SplitByLenght(string s, int split)
{
//Like using List because I can just add to it
List<string> list = new List<string>();
// Integer Division
int TimesThroughTheLoop = s.Length/split;
for (int i = 0; i < TimesThroughTheLoop; i++)
{
list.Add(s.Substring(i * split, split));
}
// Pickup the end of the string
if (TimesThroughTheLoop * split != s.Length)
{
list.Add(s.Substring(TimesThroughTheLoop * split));
}
return list.ToArray();
}
答案 10 :(得分:0)
我有一个奇怪的场景,我已经分割了一个字符串,然后在连接它们之前重新排列了段(即反转),然后我需要反转分段。以下是accepted answer by @SLaks的更新:
/// <summary>
/// Split the given string into equally-sized segments (possibly with a 'remainder' if uneven division). Optionally return the 'remainder' first.
/// </summary>
/// <param name="str">source string</param>
/// <param name="maxLength">size of each segment (except the remainder, which will be less)</param>
/// <param name="remainderFirst">if dividing <paramref name="str"/> into segments would result in a chunk smaller than <paramref name="maxLength"/> left at the end, instead take it from the beginning</param>
/// <returns>list of segments within <paramref name="str"/></returns>
/// <remarks>Original method at https://stackoverflow.com/questions/3008718/split-string-into-smaller-strings-by-length-variable </remarks>
private static IEnumerable<string> ToSegments(string str, int maxLength, bool remainderFirst = false) {
// note: `maxLength == 0` would not only not make sense, but would result in an infinite loop
if(maxLength < 1) throw new ArgumentOutOfRangeException("maxLength", maxLength, "Should be greater than 0");
// correct for the infinite loop caused by a nonsensical request of `remainderFirst == true` and no remainder (`maxLength==1` or even division)
if( remainderFirst && str.Length % maxLength == 0 ) remainderFirst = false;
var index = 0;
// note that we want to stop BEFORE we reach the end
// because if it's exact we'll end up with an
// empty segment
while (index + maxLength < str.Length)
{
// do we want the 'final chunk' first or at the end?
if( remainderFirst && index == 0 ) {
// figure out remainder size
var remainder = str.Length % maxLength;
yield return str.Substring(index, remainder);
index += remainder;
}
// normal stepthrough
else {
yield return str.Substring(index, maxLength);
index += maxLength;
}
}
yield return str.Substring(index);
}//--- fn ToSegments
(我还更正了原始while
版本中的错误,如果maxLength==1
答案 11 :(得分:0)
public List<string> SplitArray(string item, int size)
{
if (item.Length <= size) return new List<string> { item };
var temp = new List<string> { item.Substring(0,size) };
temp.AddRange(SplitArray(item.Substring(size), size));
return temp;
}
请注意,它不会返回IEnumerable而是一个列表