Я хотел бы разбить Строку определенной переменной длины.
Этому нужно к граничной проверке поэтому, поскольку не взрываются, когда последний раздел строки не пока или дольше, чем длина. Поиск самого сжатого (все же понятный) версия.
Пример:
string x = "AAABBBCC";
string[] arr = x.SplitByLength(3);
// arr[0] -> "AAA";
// arr[1] -> "BBB";
// arr[2] -> "CC"
Вам необходимо использовать цикл:
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 и альтернатива: (Для тех, кто не может стоять пока (правда)
)
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);
}
Еще один небольшой вариант (классический, но простой и прагматичный):
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();
}
}
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();
}
Это не очень лаконично, но я мог бы использовать такой метод расширения:
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
, а не массив. Если вы хотите преобразовать результат в массив, используйте ToArray
:
string[] arr = x.SplitByLength(3).ToArray();
Использование Batch
от MoreLinq
, на .Net 4.0:
public static IEnumerable<string> SplitByLength(this string str, int length)
{
return str.Batch(length, String.Concat);
}
На 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()));
}
Может быть немного неинтуитивно рассматривать строку как набор символов, поэтому можно предложить манипуляции со строкой.
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;
}
Вот что я бы сделал:
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
для " core "метод заключается в том, что string.Split
возвращает string []
, поэтому, на мой взгляд, есть приоритет для методов, имена которых начинаются с Split
, чтобы возвращать массивы.
Но это только я.
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();
}
Простая для понимания версия:
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 была хорошей константой.