2012-09-11 37 views
6

Làm cách nào để kiểm tra xem chuỗi có chứa chuỗi con không, nhưng chỉ ở một vị trí cụ thể?Kiểm tra xem một chuỗi có chứa một từ nhưng chỉ ở vị trí cụ thể không?

chuỗi Ví dụ:

yêu thích màu của bạn là gì? tôi [yêu thích] màu sắc là màu xanh

Nếu tôi muốn kiểm tra xem chuỗi chứa một từ cụ thể Tôi thường làm điều này:

var 
    S: string; 
begin 
    S := 'What is your favorite color? my [favorite] color is blue'; 
    if (Pos('favorite', S) > 0) then 
    begin 
    // 
    end; 
end; 

Những gì tôi cần là để xác định xem từ yêu thích tồn tại trong chuỗi, bỏ qua mặc dù nó xuất hiện bên trong các biểu tượng [], mà mẫu mã trên không rõ ràng.

Vì vậy, nếu chúng ta đặt mã vào một hàm boolean, một số kết quả mẫu sẽ trông như thế này:

TRUE: yêu thích màu của bạn là gì? màu của tôi [yêu thích] màu của chúng tôi là

ĐÚNG: yêu thích của bạn là gì màu? tôi [blah blah] màu sắc là màu xanh

FALSE: blah blah màu của bạn là gì? tôi [một số yêu thích] màu sắc là màu xanh

Hai mẫu đầu tiên ở trên là đúng sự thật vì yêu thích từ được tìm thấy bên ngoài của những biểu tượng [], cho dù đó là bên trong chúng hay không.

Mẫu thứ 3 là sai vì mặc dù có từ yêu thích, nó chỉ xuất hiện bên trong ký hiệu [] - chúng tôi chỉ nên kiểm tra xem nó có tồn tại bên ngoài ký hiệu hay không. Vì vậy, tôi cần một chức năng để xác định có hay không một từ (yêu thích trong ví dụ này) xuất hiện trong một chuỗi, nhưng bỏ qua thực tế nếu từ được bao quanh bên trong các ký hiệu [].

+0

Ý tưởng: 1) Tách chuỗi trên '\ s' và kiểm tra phần tử thứ 4. 2) Kiểm tra 'yêu thích' (lưu ý các khoảng trống xung quanh từ). 3) Tách chuỗi trên dấu hỏi '?' Và sau đó kiểm tra xem nó có giữ 'yêu thích' hay không. –

+5

Tìm kiếm '[', nếu tìm thấy tìm kiếm ']', xóa ở giữa bao gồm '[]', tìm kiếm mục ưa thích. –

+0

Hoặc sử dụng cụm từ thông dụng (với các đơn vị được bao gồm trong XE) với một regex của ''\ b' + wordtofind + '\ b''. Điều duy nhất bạn phải chú ý là “Nó có phải là yêu thích của bạn không?”, Nơi '? 'Sẽ làm cho nó không khớp. –

Trả lời

8

Tôi thích Sertac's idea về việc xóa chuỗi được bao quanh bởi dấu ngoặc và tìm chuỗi sau đó. Dưới đây là mẫu mã được mở rộng bằng tìm kiếm cho toàn bộ từ và độ nhạy chữ hoa chữ thường:

function ContainsWord(const AText, AWord: string; AWholeWord: Boolean = True; 
    ACaseSensitive: Boolean = False): Boolean; 
var 
    S: string; 
    BracketEnd: Integer; 
    BracketStart: Integer; 
    SearchOptions: TStringSearchOptions; 
begin 
    S := AText; 
    BracketEnd := Pos(']', S); 
    BracketStart := Pos('[', S); 
    while (BracketStart > 0) and (BracketEnd > 0) do 
    begin 
    Delete(S, BracketStart, BracketEnd - BracketStart + 1); 
    BracketEnd := Pos(']', S); 
    BracketStart := Pos('[', S); 
    end; 
    SearchOptions := [soDown]; 
    if AWholeWord then 
    Include(SearchOptions, soWholeWord); 
    if ACaseSensitive then 
    Include(SearchOptions, soMatchCase); 
    Result := Assigned(SearchBuf(PChar(S), StrLen(PChar(S)), 0, 0, AWord, 
    SearchOptions)); 
end; 

Đây là phiên bản tối ưu hóa của hàm, sử dụng lặp char con trỏ mà không cần thao tác chuỗi. So với phiên bản trước, thao tác này xử lý trường hợp khi bạn có chuỗi có dấu ngoặc đóng như ví dụ My [favorite color is. Chuỗi như vậy được đánh giá là True vì khung còn thiếu.

Nguyên tắc là đi qua toàn bộ chuỗi char bằng char và khi bạn tìm thấy dấu ngoặc mở, hãy xem liệu khung đó có cặp kết thúc cho chính nó hay không. Nếu có, hãy kiểm tra xem chuỗi con từ vị trí được lưu trữ cho đến khi dấu ngoặc mở chứa từ tìm kiếm. Nếu có, hãy thoát khỏi hàm. Nếu không, hãy di chuyển vị trí đã lưu vào giá đóng. Nếu khung mở không có cặp kết thúc riêng, hãy tìm từ đó từ vị trí được lưu trữ đến cuối toàn bộ chuỗi và thoát khỏi hàm.

Đối với phiên bản nhận xét của mã này follow this link.

function ContainsWord(const AText, AWord: string; AWholeWord: Boolean = True; 
    ACaseSensitive: Boolean = False): Boolean; 
var 
    CurrChr: PChar; 
    TokenChr: PChar; 
    TokenLen: Integer; 
    SubstrChr: PChar; 
    SubstrLen: Integer; 
    SearchOptions: TStringSearchOptions; 
begin 
    Result := False; 
    if (Length(AText) = 0) or (Length(AWord) = 0) then 
    Exit; 
    SearchOptions := [soDown]; 
    if AWholeWord then 
    Include(SearchOptions, soWholeWord); 
    if ACaseSensitive then 
    Include(SearchOptions, soMatchCase); 
    CurrChr := PChar(AText); 
    SubstrChr := CurrChr; 
    SubstrLen := 0; 
    while CurrChr^ <> #0 do 
    begin 
    if CurrChr^ = '[' then 
    begin 
     TokenChr := CurrChr; 
     TokenLen := 0; 
     while (TokenChr^ <> #0) and (TokenChr^ <> ']') do 
     begin 
     Inc(TokenChr); 
     Inc(TokenLen); 
     end; 
     if TokenChr^ = #0 then 
     SubstrLen := SubstrLen + TokenLen; 
     Result := Assigned(SearchBuf(SubstrChr, SubstrLen, 0, 0, AWord, 
     SearchOptions)); 
     if Result or (TokenChr^ = #0) then 
     Exit; 
     CurrChr := TokenChr; 
     SubstrChr := CurrChr; 
     SubstrLen := 0; 
    end 
    else 
    begin 
     Inc(CurrChr); 
     Inc(SubstrLen); 
    end; 
    end; 
    Result := Assigned(SearchBuf(SubstrChr, SubstrLen, 0, 0, AWord, 
    SearchOptions)); 
end; 
+1

Câu trả lời hay, đặc biệt hữu ích là liên kết đến câu trả lời với nhận xét, giúp dễ dàng hơn trong việc tiêu hóa và hiểu những gì đang xảy ra. –

+1

Cảm ơn! Dù sao, regex là đúng cách để làm những gì bạn cần (và chắc chắn dễ dàng hơn), nhưng mặt khác, điều này là thẳng thắn hơn với nhiệm vụ cụ thể này (và hiệu quả hơn tôi muốn nói, vì regex ít nhất cần phải phân tích cú pháp biểu thức trước khi bắt đầu khớp). Tôi muốn nói, nếu bạn sẽ không xây dựng một số trình phân tích cú pháp ví dụ, nơi bạn sẽ có nhiều nhiệm vụ tương tự như trận đấu này, sau đó giải pháp này có thể nhẹ hơn bao gồm cả regex. Nhưng lý do chính, tại sao tôi đã đăng này là không có câu trả lời ở đây được sử dụng Delphi tinh khiết. – TLama

7

Trong regular expressions, có một thứ gọi là look-around bạn có thể sử dụng. Trong trường hợp của bạn, bạn có thể giải quyết nó với lookbehind tiêu cực: bạn muốn "yêu thích" trừ khi nó được đặt trước với một khung mở. Nó có thể trông như thế này:

(?<!\[[^\[\]]*)favorite 

Từng bước: (?<! là tiền tố lookbehind tiêu cực, chúng tôi đang tìm kiếm \[ tùy chọn tiếp theo không hoặc nhiều những điều không đóng hoặc mở ngoặc: [^\[\]]*, đóng tiêu cực trông giống với ) và sau đó là favorite ngay sau đó.

+0

Tôi nghĩ rằng bạn là một giải pháp thanh lịch và thích hợp – diegoaguilar

0

Tôi nghĩ bạn có thể viết lại vấn đề của mình là "tìm một ocurrence của chuỗi được cung cấp không bị bao quanh bởi dấu ngoặc vuông". Nếu điều đó mô tả vấn đề của bạn, thì bạn có thể tiếp tục và sử dụng cụm từ thông dụng đơn giản như [^\[]favorite[^\]].

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