Thêm dấu phân cách vào chuỗi ở mỗi N ký tự?


77

Tôi có một chuỗi chứa các chữ số nhị phân. Làm thế nào để tách chuỗi sau mỗi chữ số 8?

Giả sử chuỗi là:

string x = "111111110000000011111111000000001111111100000000";

Tôi muốn thêm dấu phân tách như, (dấu phẩy) sau mỗi 8 ký tự.

đầu ra phải là:

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

Sau đó, tôi muốn gửi nó vào danh sách <> 8 ký tự cuối cùng đầu tiên rồi đến 8 ký tự trước đó (ngoại trừ,), v.v.

Tôi có thể làm cái này như thế nào?


1
bạn có thể sử dụng mảng char hoặc byte.
AliRıza Adıyahşi


tôi có thể làm điều đầu tiên với string.Format () không?
Abdur Rahim

Câu trả lời:


128
Regex.Replace(myString, ".{8}", "$0,");

Nếu bạn muốn một mảng gồm tám ký tự, thì cách sau có lẽ dễ dàng hơn:

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

sẽ chỉ chia chuỗi tại các điểm có bội số tám ký tự đứng trước nó.


1
Có thể đáng giá khi khẳng định rằng chúng chỉ là "chữ số" nhị phân, không phải bất kỳ ký tự nào: "[01]{8}"
GalacticCowboy.

4
Vâng, tôi hy vọng họ biết những loại dữ liệu mà họ ném vào :) này
Joey

Bạn có thể giải thích phần "$ 0" cho tôi không? Tôi không chắc làm thế nào mà biểu thức đó được cho là được đọc / đánh giá.
scottmgerstl,

1
Trong phần thay thế $0đề cập đến toàn bộ trận đấu ( $1là nhóm bắt đầu tiên, v.v.). Bạn cũng có thể sử dụng $&.
Joey

17
Mặc dù yêu cầu đã yêu cầu dấu phẩy ở cuối, nhưng nếu nhà phát triển không muốn dấu phẩy ở cuối, họ có thể thay đổi mẫu RegEx thành ". {8} (?! $)" Sử dụng một cái nhìn trước phủ định để đảm bảo nó không khớp với tám ký tự ở cuối chuỗi.
Josh Lyon

43

Thử cái này:

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

Vâng, thực sự ... Cảm ơn @dasbinkeblight
Abdur Rahim.

1
Nhân tiện, bạn không cần ToList(), vì string.Joinquá tải cần mộtIEnumerable (kể từ .NET 4).
Joey

1
@Joey Tôi biết, nhưng ban đầu tôi đã hiểu sai câu hỏi. Tôi đọc phần OP nói "Sau đó, tôi muốn gửi nó vào danh sách <>" và đăng một câu trả lời có ToList()và không có string.Joindòng. Sau đó, tôi đọc lại câu hỏi, thêm res = ...và lưu, nhưng tôi quên xóa ToList().
Sergey Kalinichenko

1
Có một vấn đề, sau khi thực hiện một phương pháp mở rộng. nếu chuỗi ngắn hơn thì khoảng thời gian. if (s.Length <khoảng) return s; Nhưng nếu không, hoạt động tuyệt vời.
Yogurt The Wise,

Phương thức này cắt độ dài của chuỗi. Nếu schuỗi có thêm 7 ký tự, những ký tự đó sẽ không được trả về.
Mort

3

... hoặc trường cũ:

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

1
Tôi gọi nó là dễ đọc - nhưng với mỗi người: D Khác với các phương pháp Regex ở đây, đó là những gì các phương thức Linq đang thực hiện đằng sau hậu trường - lặp lại và cắt nhỏ khi chúng đi - chỉ dễ đọc hơn nhiều. Tôi làm như phương pháp hàng loạt ở trên, đó là một cái mới vào tôi :)
Wolf5370

Điều này thậm chí sẽ không biên dịch, mặc dù lengthkhông phải là thành viên của System.String.
Joey

3

Xấu xí nhưng ít rác hơn:

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

Quá tải chuỗi:

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

3

Có một cách tiếp cận Regex khác:

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());

Tôi thích cách tiếp cận này là "mảnh là dễ hiểu", ngay cả khi phải mất một chút cắn kẹo mềm hơn trong .NET 3.5

Cảm ơn vì những bổ sung :) - Tôi tiếp tục quên kiểm tra tính tương thích của khung.
Alex

1
Mã này loại bỏ các ký tự. Dấu tách sẽ thay thế bằng chuỗi và chuỗi sẽ bị mất.
Mohsen Tavoosi محسن طاوسی

2

Nếu tôi hiểu chính xác yêu cầu cuối cùng của bạn (tôi không rõ liệu bạn có cần chuỗi phân cách bằng dấu phẩy ở giữa hay không), bạn có thể thực hiện điều này:

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

Bằng cách sử dụng morelinq .


Nếu chỉ Batchlà tiêu chuẩn :( Trong mọi trường hợp, nó tay để biết về morelinq.

1

Một cách sử dụng 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()
    );


1

Đây là hai xu nhỏ của tôi nữa. Triển khai sử dụng 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();
        }

Bạn có thể gọi nó như thế này:

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

Phương pháp này thất bại nếu str là null hoặc nếu nó ngắn hơn chunk_len
Greg

1

Tôi đã làm điều đó bằng cách sử dụng Pattern & Matcher theo cách sau:

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")
}

Ở đâu:

inputcho biết chuỗi đầu vào. Kiểm tra phần kết quả.

insertioncho biết Chèn chuỗi giữa các ký tự đó. Ví dụ: dấu phẩy (,), bắt đầu (*), băm (#).

interval cho biết bạn muốn thêm ký tự chèn vào khoảng thời gian nào.

inputcho biết chuỗi đầu vào. Kiểm tra phần kết quả. Kiểm tra phần kết quả; ở đây tôi đã thêm chèn vào mỗi ký tự thứ 4.

Các kết quả:

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

Hi vọng điêu nay co ich.


0

Điều này nhanh hơn nhiều mà không cần sao chép mảng (phiên bản này chèn khoảng trắng mỗi 3 chữ số nhưng bạn có thể điều chỉnh nó theo nhu cầu của mình)

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

Tôi không hiểu điều này. valueField nhân đôi? bạn chuyển đổi chuỗi đầu vào thành double để sử dụng nó trong hàm rồi chuyển đổi lại thành chuỗi và charArray? Bạn có phiền bình luận mã một chút không?
Joze

Tôi không có chuỗi đầu vào. Tôi chỉ có một giá trị gấp đôi, đó là lý do tại sao valueFiledlà gấp đôi. Nếu bạn có giá trị chuỗi thì bạn có thể tạo valueFiledchuỗi và thay đổi dòng đầu tiên thành char[] ins = valueField.ToCharArray();.
Mateusz Puwałowski

0

Đến bữa tiệc hơi muộn, nhưng đây là biểu thức LINQ được đơn giản hóa để chia một chuỗi đầu xvào thành các nhóm được nphân tách bằng một chuỗi khác sep:

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

Tóm tắt nhanh những gì đang xảy ra ở đây:

  • xđang được coi là một IEnumberable<char>, đó là nơi InSetsOfphương thức mở rộng xuất hiện.
  • InSetsOf(n)nhóm các ký tự thành một IEnumerabletrong số IEnumerable- mỗi mục nhập trong nhóm bên ngoài chứa một nhóm nký tự bên trong .
  • Bên trong Selectphương thức, mỗi nhóm nký tự được chuyển trở lại thành một chuỗi bằng cách sử dụng hàm String()tạo nhận một mảng chars.
  • Kết quả của Selectbây giờ là an IEnumerable<string>, được chuyển vào String.Joinđể xen vào sepchuỗi, giống như bất kỳ ví dụ nào khác.

-1

Tôi đã muộn với câu trả lời của mình nhưng bạn có thể sử dụng câu trả lời sau:

    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

Đối với mỗi 1 ký tự, bạn có thể thực hiện một chữ lót sau:

string.Join(".", "1234".ToArray()) //result: 1.2.3.4
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.