86

I have a string which contains binary digits. How to separate string after each 8 digit?

Suppose the string is:

string x = "111111110000000011111111000000001111111100000000";

I want to add a separator like ,(comma) after each 8 character.

output should be :

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

Then I want to send it to a list<> last 8 char 1st then the previous 8 chars(excepting ,) and so on.

How can I do this?

love thakker
  • 472
  • 2
  • 12
  • 27
Abdur Rahim
  • 3,825
  • 11
  • 43
  • 80

14 Answers14

142
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.

Joey
  • 330,812
  • 81
  • 665
  • 668
  • 1
    Might be worthwhile asserting that they're only binary "digits", not any character: `"[01]{8}"` – GalacticCowboy Mar 29 '12 at 19:53
  • 4
    Well, I hope they know what kind of data they throw into this :) – Joey Mar 29 '12 at 19:55
  • Can you explain the "$0," portion to me? I am not quite sure how that expression is supposed to be read/evaluated. – scottmgerstl May 29 '13 at 13:42
  • 1
    In the replacement part `$0` refers to the whole match (`$1` is the first capturing group, etc.). You can also use `$&`. – Joey May 29 '13 at 16:22
  • 24
    While the request *did* ask for the trailing comma, if the developer did not want the trailing comma, they could change the RegEx pattern to ".{8}(?!$)" which uses a negative lookahead to ensure it does not match the eight characters at the end of the string. – Josh Lyon Sep 10 '14 at 18:29
  • This code not works with any string or non-english numbers. – Mohsen Tavoosi محسن طاوسی Mar 27 '16 at 21:20
  • @MehdiDehghani, the question explicitly calls for that. But changing the regex to not do that it fairly trivial, see Josh's comment above. – Joey Dec 24 '16 at 11:08
  • 2
    If you don't want the last comma, you can use this regex `.{8}(?!$)` instead. – MIWMIB May 29 '19 at 11:15
45

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);
LoRdPMN
  • 437
  • 1
  • 4
  • 15
Sergey Kalinichenko
  • 697,062
  • 78
  • 1,055
  • 1,465
  • Yes indeed... Thanks @dasbinkeblight – Abdur Rahim Mar 29 '12 at 19:36
  • 1
    You don't need the `ToList()` by the way, as `string.Join` has [an overload that takes an `IEnumerable`](http://msdn.microsoft.com/en-us/library/dd992421.aspx) (since .NET 4). – Joey Mar 29 '12 at 19:57
  • 1
    @Joey I know, but I initially misunderstood the question. I read the part where the OP says "Then i want to send it to a list<>" part, and posted an answer with `ToList()` and no `string.Join` line. Then I re-read the question, added `res = ...`, and saved, but I forgot to remove `ToList()`. – Sergey Kalinichenko Mar 29 '12 at 20:08
  • 1
    Had one issue, after making an extension method. if the string was shorter then the interval. if (s.Length < interval) return s; But otherwise, worked great. – Yogurt The Wise Jun 28 '17 at 19:31
  • 2
    This method clips the length of the string. If the `s` string contained 7 more characters, those would not be returned. – Mort Sep 16 '20 at 06:46
3

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);
}
Johan Larsson
  • 16,394
  • 9
  • 71
  • 85
3

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());
Laurel
  • 5,771
  • 12
  • 29
  • 54
Alex
  • 7,643
  • 1
  • 40
  • 54
3

...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;
}
Wolf5370
  • 1,364
  • 11
  • 12
  • 1
    I call it easy to read - but to each their own :D Other than the Regex methods here, it is what the Linq methods are doing behind the scenes - looping through and chopping as they go - just much easier to read. I do like the Batch method above, that's a new one on me :) – Wolf5370 Mar 29 '12 at 19:53
  • This won't even compile, though, as `length` isn't a member of `System.String`. – Joey Mar 14 '14 at 08:16
2

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, ',');
C.M.
  • 329
  • 3
  • 5
2

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.

David Peden
  • 16,530
  • 6
  • 48
  • 70
  • If only `Batch` was standard :( In any case, it's hand to know about morelinq. –  Mar 29 '12 at 19:40
1

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.

Hiren Patel
  • 50,794
  • 21
  • 170
  • 147
1

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()
    );
driis
  • 156,816
  • 44
  • 266
  • 336
0

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);
}
  • I don't understand this. valueField a double? you convert the input string to double in order to use it in the function to then reconvert it to string and charArray? Would you mind commenting the code a bit? – Joze May 21 '15 at 09:04
  • I did not have input string. I just had a double value, that is why `valueFiled` is double. If you have string value then you can make `valueFiled` string and change 1st line to `char[] ins = valueField.ToCharArray();`. – Mateusz Puwałowski May 27 '15 at 13:45
0

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.
Dusty
  • 3,768
  • 2
  • 26
  • 38
0

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
Rajan
  • 292
  • 2
  • 10
-1

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;
    }
-1

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

string.Join(".", "1234".ToArray()) //result: 1.2.3.4
Ma Dude
  • 407
  • 1
  • 5
  • 14