2015-11-11 29 views
10

Vì vậy, tôi có một chuỗi mà tôi cần phải chia theo địa chỉ EmailEmail tách địa chỉ

dấu chấm phẩy của: "[email protected];,.'o"@hotmail.com;"some;thing"@example.com

Cả hai địa chỉ email có giá trị

Vì vậy, tôi muốn có a List<string> của những điều sau:

Nhưng cách tôi hiện đang tách các địa chỉ không hoạt động:

var addresses = emailAddressString.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries) 
       .Select(x => x.Trim()).ToList(); 

Do nhiều ; nhân vật tôi kết thúc với địa chỉ email không hợp lệ.

Tôi đã thử một vài cách khác nhau, thậm chí đi xuống nếu chuỗi chứa dấu ngoặc kép và sau đó tìm chỉ mục của các ký tự ; và làm theo cách đó, nhưng đó là một nỗi đau thực sự.

Có ai có đề xuất nào tốt hơn không?

+1

Đề nghị của tôi sẽ là để đảm bảo rằng nhân vật delimiter của bạn không hiển thị bất cứ nơi nào khác ngoài để đánh dấu ranh giới giữa các email, vì vậy các email có ';' như một phần của tên của chúng (ví dụ: "some; [email protected]") không được phép. Nếu không, hãy tìm một ký tự phân cách khác, giống như một đường ống '|'? – ray

+0

RegEx để giải cứu? Có thể bạn có thể điều chỉnh: http://stackoverflow.com/questions/7430186/regex-split-string-with-on-a-delimetersemi-colon-except-those-that-appear-in – Corak

+1

Hãy thử những điều sau đây: '(^ |;) (. *?) @ ([\ d \ w] + [-] *) + \. \ w + ' – Camo

Trả lời

4

Tôi rõ ràng đã bắt đầu viết phương pháp chống regex của mình vào khoảng thời gian giống như juharr (Câu trả lời khác). Tôi nghĩ rằng kể từ khi tôi đã có nó bằng văn bản tôi sẽ gửi nó.

public static IEnumerable<string> SplitEmailsByDelimiter(string input, char delimiter) 
    { 
     var startIndex = 0; 
     var delimiterIndex = 0; 

     while (delimiterIndex >= 0) 
     { 
      delimiterIndex = input.IndexOf(';', startIndex); 
      string substring = input; 
      if (delimiterIndex > 0) 
      { 
       substring = input.Substring(0, delimiterIndex); 
      } 

      if (!substring.Contains("\"") || substring.IndexOf("\"") != substring.LastIndexOf("\"")) 
      { 
       yield return substring; 
       input = input.Substring(delimiterIndex + 1); 
       startIndex = 0; 
      } 
      else 
      { 
       startIndex = delimiterIndex + 1; 
      } 
     } 
    } 

Rồi sau

  var input = "[email protected];\"[email protected];,.'o\"@hotmail.com;\"some;thing\"@example.com;[email protected];[email protected];"; 
      foreach (var email in SplitEmailsByDelimiter(input, ';')) 
      { 
       Console.WriteLine(email); 
      } 

sẽ cho sản lượng này

[email protected] 
"[email protected];,.'o"@hotmail.com 
"some;thing"@example.com 
[email protected] 
[email protected] 
13

Giả sử rằng hai dấu ngoặc kép không được phép, trừ trường hợp khai mạc và bế mạc trích trước "tại" ký @, bạn có thể sử dụng biểu thức chính quy này để nắm bắt các địa chỉ e-mail:

((?:[^@"]+|"[^"]*")@[^;]+)(?:;|$) 

Các ý tưởng là chụp một phần chưa được trích dẫn [^@"]+ hoặc phần được trích dẫn "[^"]*" trước @ và sau đó chụp mọi thứ lên đến dấu chấm phẩy ; hoặc neo cuối $.

Demo of the regex.

var input = "\"[email protected];,.'o\"@hotmail.com;\"some;thing\"@example.com;[email protected]"; 
var mm = Regex.Matches(input, "((?:[^@\"]+|\"[^\"]*\")@[^;]+)(?:;|$)"); 
foreach (Match m in mm) { 
    Console.WriteLine(m.Groups[1].Value); 
} 

in Mã này

"[email protected];,.'o"@hotmail.com 
"some;thing"@example.com 
[email protected] 

Demo 1.

Nếu bạn muốn cho phép thoát hai dấu ngoặc kép bên trong hai dấu ngoặc kép, bạn có thể sử dụng một biểu thức phức tạp hơn:

((?:(?:[^@\"]|(?<=\\)\")+|\"([^\"]|(?<=\\)\")*\")@[^;]+)(?:;|$) 

Mọi thứ khác vẫn giữ nguyên.

Demo 2.

+0

Cảm ơn sự giúp đỡ của bạn. Được kéo tóc của tôi ra về điều này! –

+0

Điều gì sẽ xảy ra nếu báo giá kép được phép? –

+0

@JamieR Tùy thuộc vào quy tắc cho phép thêm dấu ngoặc kép. Nếu thêm dấu ngoặc kép được cho phép bên trong các chuỗi được trích dẫn, nhưng chúng phải được thoát, thì phần này "" [^ "] *" 'của regex sẽ trở nên phức tạp hơn nhiều, nhưng vẫn có thể thực hiện được. – dasblinkenlight

3

Bạn cũng có thể làm điều này mà không sử dụng cụm từ thông dụng. Phương pháp mở rộng sau đây sẽ cho phép bạn chỉ định ký tự dấu tách và ký tự để bắt đầu và kết thúc chuỗi thoát. Lưu ý rằng nó không xác nhận rằng tất cả các chuỗi thoát được đóng lại.

public static IEnumerable<string> SpecialSplit(
    this string str, char delimiter, char beginEndEscape) 
{ 
    int beginIndex = 0; 
    int length = 0; 
    bool escaped = false; 
    foreach (char c in str) 
    { 
     if (c == beginEndEscape) 
     { 
      escaped = !escaped; 
     } 

     if (!escaped && c == delimiter) 
     { 
      yield return str.Substring(beginIndex, length); 
      beginIndex += length + 1; 
      length = 0; 
      continue; 
     } 

     length++; 
    } 

    yield return str.Substring(beginIndex, length); 
} 

Rồi sau

var input = "\"[email protected];,.'o\"@hotmail.com;\"some;thing\"@example.com;[email protected];\"D;[email protected];blah.com\""; 
foreach (var address in input.SpecialSplit(';', '"')) 
    Console.WriteLine(v); 

Trong khi cung cấp cho sản lượng này

"[email protected];,.'o"@hotmail.com

"một số; điều" @ example.com

hello @ world

"D; D @ blah; blah.com"

Dưới đây là phiên bản làm việc với một nhân vật thoát đơn bổ sung. Nó giả định rằng hai ký tự thoát liên tiếp sẽ trở thành một ký tự thoát duy nhất và nó thoát khỏi cả hai điều lệ beginEndEscape để nó sẽ không kích hoạt đầu hoặc cuối của một chuỗi thoát và nó cũng thoát khỏi delimiter. Bất kỳ thứ gì khác xuất hiện sau ký tự thoát sẽ được để lại như với ký tự thoát được loại bỏ.

public static IEnumerable<string> SpecialSplit(
    this string str, char delimiter, char beginEndEscape, char singleEscape) 
{ 
    StringBuilder builder = new StringBuilder(); 
    bool escapedSequence = false; 
    bool previousEscapeChar = false; 
    foreach (char c in str) 
    { 
     if (c == singleEscape && !previousEscapeChar) 
     { 
      previousEscapeChar = true; 
      continue; 
     } 

     if (c == beginEndEscape && !previousEscapeChar) 
     { 
      escapedSequence = !escapedSequence; 
     } 

     if (!escapedSequence && !previousEscapeChar && c == delimiter) 
     { 
      yield return builder.ToString(); 
      builder.Clear(); 
      continue; 
     } 

     builder.Append(c); 
     previousEscapeChar = false; 
    } 

    yield return builder.ToString(); 
} 

Cuối cùng, bạn có lẽ nên thêm null kiểm tra cho chuỗi được thông qua tại và lưu ý rằng cả hai sẽ trở lại một chuỗi với một chuỗi rỗng nếu bạn vượt qua trong một chuỗi rỗng.

+0

Điều gì sẽ xảy ra nếu bên trong '' 'có một' '' '' khác.(),:; <> [] \ ". RẤT. \" rất @ \ \ "rất \". khác thường "@ strange.example.com' –

+0

Trong trường hợp đó bạn cũng cần phải nói với nó rằng có một ký tự thoát cho câu trích dẫn kép. Ngoài ra, bạn phải suy nghĩ về những gì có thể và không thể thoát được Giả sử "\\" sẽ cung cấp cho bạn một dấu gạch chéo ngược duy nhất, nhưng những gì về "\ t". Bạn có muốn một tab hoặc giống như ingle t? – juharr

+3

Ngoài ra tôi có lẽ sẽ từ bỏ bằng cách sử dụng 'string.Substring' và thay vào đó sử dụng một' StringBuilder' để thêm các ký tự khi tôi lặp qua dữ liệu. – juharr

Các vấn đề liên quan