2010-01-29 32 views
11

Thông tin nhập của tôi bao gồm các chuỗi do người dùng đăng.Regex: cách nhận các từ từ một chuỗi (C#)

Điều tôi muốn làm là tạo từ điển có các từ và tần suất chúng được sử dụng. Điều này có nghĩa là tôi muốn phân tích chuỗi, xóa tất cả rác và nhận danh sách các từ làm đầu ra.

Ví dụ, nói đầu vào là "#@[email protected] YOU'VE BEEN \***PWN3D*** ! :') !!!1einszwei drei !"

Sản lượng tôi cần là danh sách:

  • "LOLOLOL"
  • "YOU'VE"
  • "BEEN"
  • "PWN3D"
  • "einszwei"
  • "drei"

Tôi không phải người hùng ở biểu thức thông thường và đã được Googling, nhưng vỉa Google-kungfu của tôi là yếu & hellip;

Làm cách nào để chuyển từ đầu vào sang đầu ra mong muốn?

+3

http://regular-expressions.info – Jason

Trả lời

18

Regex đơn giản:

\w+

này phù hợp với một chuỗi ký tự "từ". Đó là gần như những gì bạn muốn.

Đây là một chút chính xác hơn:

\w(?<!\d)[\w'-]*

Nó phù hợp với bất kỳ số lượng ký tự văn bản, đảm bảo rằng các ký tự đầu tiên không phải là một chữ số.

Dưới đây là trận đấu của tôi:

1 lololol
2 bạn đã
3 ĐƯỢC
4 PWN3D
5 einszwei
6 Drei

Bây giờ, đó là giống như nó.

CHỈNH SỬA:
Lý do cho giao diện tiêu cực, là một số hương vị regex hỗ trợ các ký tự Unicode. Sử dụng [a-zA-Z] sẽ bỏ lỡ một vài "từ" ký tự được mong muốn. Việc cho phép \w và không cho phép \d bao gồm tất cả các ký tự Unicode có thể bắt đầu một từ trong bất kỳ khối văn bản nào.

EDIT 2:
Tôi đã tìm thấy một cách ngắn gọn hơn để có được những tác động của lookbehind tiêu cực: đúp lớp nhân vật tiêu cực với một loại trừ tiêu cực duy nhất.

[^\W\d][\w'-]*(?<=\w)

Đây là giống như trên ngoại trừ rằng nó cũng đảm bảo rằng từ kết thúc với một nhân vật từ. Và, cuối cùng, có:

[^\W\d](\w|[-']{1,2}(?=\w))*

Đảm bảo rằng không có hơn hai phi word-ký tự trong một hàng. Aka, Nó khớp với từ "up-up" nhưng không phải là "word-up", có ý nghĩa. Nếu bạn muốn nó khớp "word - up", nhưng không phải "word --- up", bạn có thể thay đổi 2 thành 3.

+0

Cảm ơn bạn rất nhiều, hoạt động như một sự quyến rũ! :) – Led

+0

@Led: Bạn có thể muốn kiểm tra Regex ở phần cuối của chỉnh sửa # 2. Nó có thể gần hơn một chút so với những gì bạn đang tìm kiếm. –

+0

được giảm giá. Các từ có ký hiệu ''' được chia thành các phần –

5

Bạn nên xem xét xử lý ngôn ngữ tự nhiên (NLP), không phải biểu thức chính quy và nếu bạn đang nhắm mục tiêu nhiều ngôn ngữ nói, bạn cũng cần phải tính đến yếu tố đó. Vì bạn đang sử dụng C#, hãy xem dự án SharpNLP.

Chỉnh sửa: Cách tiếp cận này chỉ cần thiết nếu bạn quan tâm đến nội dung ngữ nghĩa của các từ bạn đang cố chia nhỏ.

+1

Cảm ơn rất nhiều cho phản ứng!:) Nhưng hãy giữ cho nó đơn giản và nói rằng tôi không quan tâm đến ngôn ngữ - - Tôi sẽ chỉ xem xét các từ với tùy chọn '' 'và/hoặc một ký tự' - '? – Led

+1

@Giống như Atlas, liên kết tốt đẹp. +1 – Gabe

+0

Nếu bạn không quan tâm đến ngôn ngữ, thì tại sao không chỉ string.Replace() tất cả các ký tự bạn không muốn và sau đó string.Split() nó trên ký tự không gian? Không cần biểu thức thông thường. –

2

Bạn không nhất thiết cần một regex cho điều này, nếu tokenizing là tất cả các bạn đang làm. Trước tiên, bạn có thể khử trùng chuỗi bằng cách xóa tất cả các ký tự không phải chữ cái trừ khoảng trắng và sau đó thực hiện Split() trên ký tự khoảng trắng. Điều đó sẽ làm việc cho hầu hết mọi thứ, mặc dù các cơn co thắt có thể khó khăn. Điều đó sẽ giúp bạn bắt đầu ít nhất.

+0

Được rồi, vì vậy những gì tôi muốn làm là xóa tất cả các ký tự không hợp lệ, nhưng ký tự 'và - cũng không hợp lệ NẾU chúng không nằm giữa các ký tự chữ cái. (trong "word-up" the - là hợp lệ, trong "word ----- up" các ký tự phải được loại bỏ ...) – Led

+0

bạn có thể đặt một kiểm tra trong đó sẽ xem xét nếu ''' hoặc '-' được bao quanh bởi các ký tự chữ cái và nếu chúng có, đừng xóa. – Jason

0

Cảm giác ruột của tôi sẽ không sử dụng cụm từ thông dụng, nhưng chỉ cần thực hiện một hoặc hai vòng lặp.

Lặp lại từng char trong chuỗi, nếu không phải là char hợp lệ, hãy thay thế bằng một khoảng trắng Sau đó, sử dụng String.Split() và chia tách các khoảng trắng.

Dấu móc nối và dấu gạch ngang có thể phức tạp hơn một chút để xác định xem chúng có phải là ký tự rác hoặc ký tự hợp pháp hay không. Nhưng nếu bạn đang sử dụng vòng lặp for để lặp qua chuỗi sau đó nhìn về phía sau và tiến lên từ ký tự hiện tại sẽ giúp bạn.

Sau đó, bạn sẽ có danh sách các từ - cho mỗi từ này kiểm tra xem chúng có hợp lệ trong từ điển của bạn hay không. Nếu bạn muốn điều này được nhanh chóng, thực hiện somekind tìm kiếm nhị phân sẽ là tốt nhất. Nhưng chỉ để có được nó làm việc một tìm kiếm tuyến tính sẽ dễ dàng hơn để bắt đầu với.

CHỈNH SỬA: Tôi chỉ đề cập đến từ điển vì tôi nghĩ bạn có thể chỉ quan tâm đến những từ hợp pháp, tức là không phải là "asdfasdf" nhưng bỏ qua câu cuối cùng nếu đó không phải là thứ bạn cần.

+0

bạn không muốn thay thế ký tự không hợp lệ w/dấu cách. – Jason

2

Sử dụng sau

var pattern = new Regex(
    @"([^\W_\d]    # starting with a letter 
          # followed by a run of either... 
     ([^\W_\d] |   # more letters or 
     [-'\d](?=[^\W_\d]) # ', -, or digit followed by a letter 
    )* 
     [^\W_\d]    # and finishing with a letter 
    )", 
    RegexOptions.IgnorePatternWhitespace); 

var input = "#@[email protected] YOU'VE BEEN *PWN3D* ! :') !!!1einszwei drei foo--bar!"; 

foreach (Match m in pattern.Matches(input)) 
    Console.WriteLine("[{0}]", m.Groups[1].Value); 

sản lượng sản xuất của

[LOLOLOL] 
[YOU'VE] 
[BEEN] 
[PWN3D] 
[einszwei] 
[drei] 
[foo] 
[bar]
+0

bạn có thể viết regex bình thường không? Tôi có nghĩa là dòng đơn không có ký tự phụ –

+0

Giải thích tốt. – AnthonyVO

0

tôi đã viết một phần mở rộng cho chuỗi như thế này:

private static string[] GetWords(string text) 
    { 
     List<string> lstreturn = new List<string>(); 
     List<string> lst = text.Split(new[] { ' ' }).ToList(); 
     foreach (string str in lst) 
     { 
      if (str.Trim() == "") 
      { 
       lstreturn.Add(str); 
      } 
     } 
     return lstreturn.ToArray(); 
    } 
+0

Điều này không có vẻ giống như một phần mở rộng cho tôi. Bạn đang thiếu một 'this'? –

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