在每 N 个字符处为字符串添加分隔符?

我有一个包含二进制数字的字符串。如何在每个8位数字后分开字符串?

假设字符串是:

string x = "111111110000000011111111000000001111111100000000";

我想在每8个字符后面添加一个分隔符,比如,(逗号)。

产出应为:

"11111111,00000000,11111111,00000000,11111111,00000000,"

然后我想把它发送到一个列表 < > last 8 char 第一个,然后是前面的8个字符(除外) ,以此类推。

我怎么能这么做?

96500 次浏览
Regex.Replace(myString, ".{8}", "$0,");

If you want an array of eight-character strings, then the following is probably easier:

Regex.Split(myString, "(?<=^(.{8})+)");

which will split the string only at points where a multiple of eight characters precede it.

Try this:

var s = "111111110000000011111111000000001111111100000000";
var list = Enumerable
.Range(0, s.Length/8)
.Select(i => s.Substring(i*8, 8));
var res = string.Join(",", list);

If I understand your last requirement correctly (it's not clear to me if you need the intermediate comma-delimited string or not), you could do this:

var enumerable = "111111110000000011111111000000001111111100000000".Batch(8).Reverse();

By utilizing morelinq.

One way using LINQ:

string data = "111111110000000011111111000000001111111100000000";
const int separateOnLength = 8;


string separated = new string(
data.Select((x,i) => i > 0 && i % separateOnLength == 0 ? new [] { ',', x } : new [] { x })
.SelectMany(x => x)
.ToArray()
);

There's another Regex approach:

var str = "111111110000000011111111000000001111111100000000";
# for .NET 4
var res = String.Join(",",Regex.Matches(str, @"\d{8}").Cast<Match>());


# for .NET 3.5
var res = String.Join(",", Regex.Matches(str, @"\d{8}")
.OfType<Match>()
.Select(m => m.Value).ToArray());

...or old school:

public static List<string> splitter(string in, out string csv)
{
if (in.length % 8 != 0) throw new ArgumentException("in");
var lst = new List<string>(in/8);


for (int i=0; i < in.length / 8; i++) lst.Add(in.Substring(i*8,8));


csv = string.Join(",", lst); //This we want in input order (I believe)
lst.Reverse(); //As we want list in reverse order (I believe)


return lst;
}

Ugly but less garbage:

private string InsertStrings(string s, int insertEvery, char insert)
{
char[] ins = s.ToCharArray();
int length = s.Length + (s.Length / insertEvery);
if (ins.Length % insertEvery == 0)
{
length--;
}
var outs = new char[length];
long di = 0;
long si = 0;
while (si < s.Length - insertEvery)
{
Array.Copy(ins, si, outs, di, insertEvery);
si += insertEvery;
di += insertEvery;
outs[di] = insert;
di ++;
}
Array.Copy(ins, si, outs, di, ins.Length - si);
return new string(outs);
}

String overload:

private string InsertStrings(string s, int insertEvery, string insert)
{
char[] ins = s.ToCharArray();
char[] inserts = insert.ToCharArray();
int insertLength = inserts.Length;
int length = s.Length + (s.Length / insertEvery) * insert.Length;
if (ins.Length % insertEvery == 0)
{
length -= insert.Length;
}
var outs = new char[length];
long di = 0;
long si = 0;
while (si < s.Length - insertEvery)
{
Array.Copy(ins, si, outs, di, insertEvery);
si += insertEvery;
di += insertEvery;
Array.Copy(inserts, 0, outs, di, insertLength);
di += insertLength;
}
Array.Copy(ins, si, outs, di, ins.Length - si);
return new string(outs);
}

This is much faster without copying array (this version inserts space every 3 digits but you can adjust it to your needs)

public string GetString(double valueField)
{
char[] ins = valueField.ToString().ToCharArray();
int length = ins.Length + (ins.Length / 3);
if (ins.Length % 3 == 0)
{
length--;
}
char[] outs = new char[length];


int i = length - 1;
int j = ins.Length - 1;
int k = 0;
do
{
if (k == 3)
{
outs[i--] = ' ';
k = 0;
}
else
{
outs[i--] = ins[j--];
k++;
}
}
while (i >= 0);


return new string(outs);
}

A little late to the party, but here's a simplified LINQ expression to break an input string x into groups of n separated by another string sep:

string sep = ",";
int n = 8;
string result = String.Join(sep, x.InSetsOf(n).Select(g => new String(g.ToArray())));

A quick rundown of what's happening here:

  • x is being treated as an IEnumberable<char>, which is where the InSetsOf extension method comes in.
  • InSetsOf(n) groups characters into an IEnumerable of IEnumerable -- each entry in the outer grouping contains an inner group of n characters.
  • Inside the Select method, each group of n characters is turned back into a string by using the String() constructor that takes an array of chars.
  • The result of Select is now an IEnumerable<string>, which is passed into String.Join to interleave the sep string, just like any other example.

I am more than late with my answer but you can use this one:

    static string PutLineBreak(string str, int split)
{
for (int a = 1; a <= str.Length; a++)
{
if (a % split == 0)
str = str.Insert(a, "\n");
}


return str;
}

For every 1 character, you could do this one-liner:

string.Join(".", "1234".ToArray()) //result: 1.2.3.4

Here my two little cents too. An implementation using StringBuilder:

        public static string AddChunkSeparator (string str, int chunk_len, char separator)
{
if (str == null || str.Length < chunk_len) {
return str;
}
StringBuilder builder = new StringBuilder();
for (var index = 0; index < str.Length; index += chunk_len) {
builder.Append(str, index, chunk_len);
builder.Append(separator);
}
return builder.ToString();
}

You can call it like this:

string data = "111111110000000011111111000000001111111100000000";
string output = AddChunkSeparator(data, 8, ',');

I did it using Pattern & Matcher as following way:

fun addAnyCharacter(input: String, insertion: String, interval: Int): String {
val pattern = Pattern.compile("(.{$interval})", Pattern.DOTALL)
val matcher = pattern.matcher(input)
return matcher.replaceAll("$1$insertion")
}

Where:

input indicates Input string. Check results section.

insertion indicates Insert string between those characters. For example comma (,), start(*), hash(#).

interval indicates at which interval you want to add insertion character.

input indicates Input string. Check results section. Check results section; here I've added insertion at every 4th character.

Results:

I/P: 1234XXXXXXXX5678 O/P: 1234 XXXX XXXX 5678

I/P: 1234567812345678 O/P: 1234 5678 1234 5678

I/P: ABCDEFGHIJKLMNOP O/P: ABCD EFGH IJKL MNOP

Hope this helps.

If you intend to create your own function to acheive this without using regex or pattern matching methods, you can create a simple function like this:

String formatString(String key, String seperator, int afterEvery){
String formattedKey = "";
for(int i=0; i<key.length(); i++){
formattedKey += key.substring(i,i+1);
if((i+1)%afterEvery==0)
formattedKey += seperator;
}
if(formattedKey.endsWith("-"))
formattedKey = formattedKey.substring(0,formattedKey.length()-1);
return formattedKey;
}

Calling the mothod like this

formatString("ABCDEFGHIJKLMNOPQRST", "-", 4)

Would result in the return string as this

ABCD-EFGH-IJKL-MNOP-QRST

As of .Net 6, you can simply use the IEnumerable.Chunk method (Which splits elements of a sequence into chunks) then reconcatenate the chunks using String.Join.

var text = "...";
string.Join(',', text.Chunk(size: 6).Select(x => new string(x)));