假设我有一个字符串:
string str = "1111222233334444";
Run Code Online (Sandbox Code Playgroud)
如何将这个字符串分成几个大小的块?
例如,将其分解为4将返回字符串:
"1111"
"2222"
"3333"
"4444"
Run Code Online (Sandbox Code Playgroud)
Kon*_*rin 223
static IEnumerable<string> Split(string str, int chunkSize)
{
return Enumerable.Range(0, str.Length / chunkSize)
.Select(i => str.Substring(i * chunkSize, chunkSize));
}
Run Code Online (Sandbox Code Playgroud)
请注意,可能需要额外的代码才能正常处理边缘情况(null
或空输入字符串chunkSize == 0
,输入字符串长度不能被整除chunkSize
等).原始问题没有规定对这些边缘情况的任何要求,并且在现实生活中,要求可能会有所不同,因此它们超出了本答案的范围.
Eam*_*nne 127
结合鸽子+康斯坦丁的答案......
static IEnumerable<string> WholeChunks(string str, int chunkSize) {
for (int i = 0; i < str.Length; i += chunkSize)
yield return str.Substring(i, chunkSize);
}
Run Code Online (Sandbox Code Playgroud)
这将适用于可以拆分为整数块的所有字符串,否则将抛出异常.
如果要支持任何长度的字符串,可以使用以下代码:
static IEnumerable<string> ChunksUpto(string str, int maxChunkSize) {
for (int i = 0; i < str.Length; i += maxChunkSize)
yield return str.Substring(i, Math.Min(maxChunkSize, str.Length-i));
}
Run Code Online (Sandbox Code Playgroud)
然而,在OP明确表示他并不会需要这个; 它有点长,更难阅读,稍慢.根据KISS和YAGNI的精神,我会选择第一个选项:它可能是最有效的实现,而且它非常简短,可读,并且重要的是,它会对不合格的输入抛出异常.
dov*_*ove 51
为什么不循环?这里有一些非常好的东西:
string str = "111122223333444455";
int chunkSize = 4;
int stringLength = str.Length;
for (int i = 0; i < stringLength ; i += chunkSize)
{
if (i + chunkSize > stringLength) chunkSize = stringLength - i;
Console.WriteLine(str.Substring(i, chunkSize));
}
Console.ReadLine();
Run Code Online (Sandbox Code Playgroud)
我不知道你怎么处理字符串不是4的因素,但不是说你的想法是不可能的,只是想知道它的动机,如果一个简单的for循环做得很好?显然,上述内容可以清理,甚至可以作为扩展方法.
或者如评论中所述,你知道它是/ 4
str = "1111222233334444";
for (int i = 0; i < stringLength; i += chunkSize)
{Console.WriteLine(str.Substring(i, chunkSize));}
Run Code Online (Sandbox Code Playgroud)
Mag*_*ron 45
从.NET 6开始,我们还可以使用以下Chunk
方法:
var result = str
.Chunk(4)
.Select(x => new string(x))
.ToList();
Run Code Online (Sandbox Code Playgroud)
Joã*_*lva 38
使用正则表达式和Linq:
List<string> groups = (from Match m in Regex.Matches(str, @"\d{4}")
select m.Value).ToList();
Run Code Online (Sandbox Code Playgroud)
我发现这更具可读性,但这仅仅是个人观点.它也可以是单行:).
ole*_*sii 33
这是基于@dove解决方案,但实现为扩展方法.
优点:
码
public static class EnumerableEx
{
public static IEnumerable<string> SplitBy(this string str, int chunkLength)
{
if (String.IsNullOrEmpty(str)) throw new ArgumentException();
if (chunkLength < 1) throw new ArgumentException();
for (int i = 0; i < str.Length; i += chunkLength)
{
if (chunkLength + i > str.Length)
chunkLength = str.Length - i;
yield return str.Substring(i, chunkLength);
}
}
}
Run Code Online (Sandbox Code Playgroud)
用法
var result = "bobjoecat".SplitBy(3); // bob, joe, cat
Run Code Online (Sandbox Code Playgroud)
为简洁起见,删除了单元测试(参见上一版本)
Ala*_*ore 20
这对于一个班轮怎么样?
List<string> result = new List<string>(Regex.Split(target, @"(?<=\G.{4})", RegexOptions.Singleline));
Run Code Online (Sandbox Code Playgroud)
使用这个正则表达式,最后一个块是否少于四个字符并不重要,因为它只会查看它背后的字符.我确信这不是最有效的解决方案,但我只是不得不把它扔掉.:d
它不漂亮而且不快,但它有效,它是一个单行,它是LINQy:
List<string> a = text.Select((c, i) => new { Char = c, Index = i }).GroupBy(o => o.Index / 4).Select(g => new String(g.Select(o => o.Char).ToArray())).ToList();
Run Code Online (Sandbox Code Playgroud)
我最近不得不写一些在工作中完成这个的东西,所以我想我会发布我的解决方案来解决这个问题.作为一个额外的好处,这个解决方案的功能提供了一种方法,以相反的方向分割字符串,它正确处理unicode字符,如上面Marvin Pinto所述.所以,这里是:
using System;
using Extensions;
namespace TestCSharp
{
class Program
{
static void Main(string[] args)
{
string asciiStr = "This is a string.";
string unicodeStr = "?????????";
string[] array1 = asciiStr.Split(4);
string[] array2 = asciiStr.Split(-4);
string[] array3 = asciiStr.Split(7);
string[] array4 = asciiStr.Split(-7);
string[] array5 = unicodeStr.Split(5);
string[] array6 = unicodeStr.Split(-5);
}
}
}
namespace Extensions
{
public static class StringExtensions
{
/// <summary>Returns a string array that contains the substrings in this string that are seperated a given fixed length.</summary>
/// <param name="s">This string object.</param>
/// <param name="length">Size of each substring.
/// <para>CASE: length > 0 , RESULT: String is split from left to right.</para>
/// <para>CASE: length == 0 , RESULT: String is returned as the only entry in the array.</para>
/// <para>CASE: length < 0 , RESULT: String is split from right to left.</para>
/// </param>
/// <returns>String array that has been split into substrings of equal length.</returns>
/// <example>
/// <code>
/// string s = "1234567890";
/// string[] a = s.Split(4); // a == { "1234", "5678", "90" }
/// </code>
/// </example>
public static string[] Split(this string s, int length)
{
System.Globalization.StringInfo str = new System.Globalization.StringInfo(s);
int lengthAbs = Math.Abs(length);
if (str == null || str.LengthInTextElements == 0 || lengthAbs == 0 || str.LengthInTextElements <= lengthAbs)
return new string[] { str.ToString() };
string[] array = new string[(str.LengthInTextElements % lengthAbs == 0 ? str.LengthInTextElements / lengthAbs: (str.LengthInTextElements / lengthAbs) + 1)];
if (length > 0)
for (int iStr = 0, iArray = 0; iStr < str.LengthInTextElements && iArray < array.Length; iStr += lengthAbs, iArray++)
array[iArray] = str.SubstringByTextElements(iStr, (str.LengthInTextElements - iStr < lengthAbs ? str.LengthInTextElements - iStr : lengthAbs));
else // if (length < 0)
for (int iStr = str.LengthInTextElements - 1, iArray = array.Length - 1; iStr >= 0 && iArray >= 0; iStr -= lengthAbs, iArray--)
array[iArray] = str.SubstringByTextElements((iStr - lengthAbs < 0 ? 0 : iStr - lengthAbs + 1), (iStr - lengthAbs < 0 ? iStr + 1 : lengthAbs));
return array;
}
}
}
Run Code Online (Sandbox Code Playgroud)
此外,这是运行此代码的结果的图像链接:http://i.imgur.com/16Iih.png
小智 6
我个人更喜欢我的解决方案:-)
它处理:
它是作为扩展方法实现的,并且它预先计算将要生成的块的数量。它检查最后一个块,因为如果文本长度不是倍数,则需要更短。干净、简短、易于理解...并且有效!
public static string[] Split(this string value, int chunkSize)
{
if (string.IsNullOrEmpty(value))
throw new ArgumentException("The string cannot be null.");
if (chunkSize < 1)
throw new ArgumentException("The chunk size should be equal or greater than one.");
int remainder;
int divResult = Math.DivRem(value.Length, chunkSize, out remainder);
int numberOfChunks = remainder > 0 ? divResult + 1 : divResult;
var result = new string[numberOfChunks];
int i = 0;
while (i < numberOfChunks - 1)
{
result[i] = value.Substring(i * chunkSize, chunkSize);
i++;
}
int lastChunkSize = remainder > 0 ? remainder : chunkSize;
result[i] = value.Substring(i * chunkSize, lastChunkSize);
return result;
}
Run Code Online (Sandbox Code Playgroud)
这应该比使用LINQ或此处使用的其他方法更快更有效.
public static IEnumerable<string> Splice(this string s, int spliceLength)
{
if (s == null)
throw new ArgumentNullException("s");
if (spliceLength < 1)
throw new ArgumentOutOfRangeException("spliceLength");
if (s.Length == 0)
yield break;
var start = 0;
for (var end = spliceLength; end < s.Length; end += spliceLength)
{
yield return s.Substring(start, spliceLength);
start = end;
}
yield return s.Substring(start);
}
Run Code Online (Sandbox Code Playgroud)
您可以使用Jon Skeet 的morelinq。使用批处理,如:
string str = "1111222233334444";
int chunkSize = 4;
var chunks = str.Batch(chunkSize).Select(r => new String(r.ToArray()));
Run Code Online (Sandbox Code Playgroud)
这将为 string 返回 4 个块"1111222233334444"
。如果字符串长度小于或等于块大小Batch
将返回字符串作为唯一元素IEnumerable<string>
对于输出:
foreach (var chunk in chunks)
{
Console.WriteLine(chunk);
}
Run Code Online (Sandbox Code Playgroud)
它会给:
1111
2222
3333
4444
Run Code Online (Sandbox Code Playgroud)
简单而简短:
// this means match a space or not a space (anything) up to 4 characters
var lines = Regex.Matches(str, @"[\s\S]{0,4}").Cast<Match>().Select(x => x.Value);
Run Code Online (Sandbox Code Playgroud)
我知道问题已经存在多年了,但这里有一个 Rx 实现。它length % chunkSize != 0
开箱即用地处理问题:
public static IEnumerable<string> Chunkify(this string input, int size)
{
if(size < 1)
throw new ArgumentException("size must be greater than 0");
return input.ToCharArray()
.ToObservable()
.Buffer(size)
.Select(x => new string(x.ToArray()))
.ToEnumerable();
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
180622 次 |
最近记录: |