2016-03-07 43 views
9

Tôi sử dụng StrUtils để chia chuỗi thành TStringDynArray, nhưng đầu ra không như mong đợi. Tôi sẽ cố gắng để giải thích vấn đề này:StrUtils.SplitString không hoạt động như mong đợi

Tôi có một chuỗi str: 'a'; 'b'; 'c'
Bây giờ tôi gọi StrUtils.SplitString(str, '; '); để phân chia các chuỗi và tôi mong đợi một mảng với ba yếu tố: 'a', 'b', 'c'

Nhưng những gì tôi có một mảng với năm phần tử: 'a', '', 'b', '', 'c'.
Khi tôi chia nhỏ chỉ với ';' thay vì '; ' Tôi nhận được ba phần tử có dấu trống hàng đầu.

Vậy tại sao tôi nhận được chuỗi trống trong giải pháp đầu tiên của mình?

+3

Đọc tài liệu. Có lẽ không như mong đợi, nhưng nó hoạt động như tài liệu. –

+0

Câu hỏi này có một số gợi ý về tách một chuỗi, dựa trên chuỗi ký tự nhiều (bạn mong đợi nó đang làm), nhưng hầu hết trong số chúng hoạt động với danh sách chuỗi chứ không phải mảng: http://stackoverflow.com/questions/15424293/làm thế nào để chia nhỏ chuỗi-by-a-đa-ký tự-delimiter – quasoft

Trả lời

15

Chức năng này được thiết kế để không hợp nhất các dấu phân tách liên tiếp. Ví dụ: xem xét tách chuỗi sau trên dấu phẩy:

foo,,bar 

Bạn mong đợi gì SplitString('foo,,bar', ',') để trả lại? Bạn có đang tìm kiếm ('foo', 'bar') hoặc câu trả lời là ('foo', '', 'bar')? Nó không phải là một ưu tiên mà là đúng, và các trường hợp sử dụng khác nhau có thể muốn đầu ra khác nhau.

Nếu trường hợp của bạn, bạn chỉ định hai dấu phân cách, ';'' '. Điều này có nghĩa rằng

'a'; 'b' 

chia rẽ tại ';' và một lần nữa tại ' '. Giữa hai dấu phân cách đó không có gì, và do đó một chuỗi rỗng được trả về ở giữa 'a''b'.

Phương pháp Split từ string helper được giới thiệu trong XE3 có thông số TStringSplitOptions. Nếu bạn vượt qua ExcludeEmpty cho thông số đó thì các dấu phân cách liên tiếp được coi là một dấu tách đơn. Chương trình này:

{$APPTYPE CONSOLE} 

uses 
    System.SysUtils; 

var 
    S: string; 

begin 
    for S in '''a''; ''b''; ''c'''.Split([';', ' '], ExcludeEmpty) do begin 
    Writeln(S); 
    end; 
end. 

kết quả đầu ra:

 
'a' 
'b' 
'c' 

Nhưng bạn không có điều này có sẵn cho bạn trong XE2 vì vậy tôi nghĩ rằng bạn sẽ phải cuộn chức năng phân chia của riêng bạn. Điều này có thể trông giống như sau:

function IsSeparator(const C: Char; const Separators: string): Boolean; 
var 
    sep: Char; 
begin 
    for sep in Separators do begin 
    if sep=C then begin 
     Result := True; 
     exit; 
    end; 
    end; 
    Result := False; 
end; 

function Split(const Str, Separators: string): TArray<string>; 
var 
    CharIndex, ItemIndex: Integer; 
    len: Integer; 
    SeparatorCount: Integer; 
    Start: Integer; 
begin 
    len := Length(Str); 
    if len=0 then begin 
    Result := nil; 
    exit; 
    end; 

    SeparatorCount := 0; 
    for CharIndex := 1 to len do begin 
    if IsSeparator(Str[CharIndex], Separators) then begin 
     inc(SeparatorCount); 
    end; 
    end; 

    SetLength(Result, SeparatorCount+1); // potentially an over-allocation 
    ItemIndex := 0; 
    Start := 1; 
    CharIndex := 1; 
    for CharIndex := 1 to len do begin 
    if IsSeparator(Str[CharIndex], Separators) then begin 
     if CharIndex>Start then begin 
     Result[ItemIndex] := Copy(Str, Start, CharIndex-Start); 
     inc(ItemIndex); 
     end; 
     Start := CharIndex+1; 
    end; 
    end; 

    if len>Start then begin 
    Result[ItemIndex] := Copy(Str, Start, len-Start+1); 
    inc(ItemIndex); 
    end; 

    SetLength(Result, ItemIndex); 
end; 

Tất nhiên điều này giả định rằng bạn muốn một khoảng trống hoạt động như một dấu tách. Bạn đã yêu cầu điều đó trong mã, nhưng có lẽ bạn thực sự chỉ muốn ; hoạt động như một dấu tách. Trong trường hợp đó, bạn có thể muốn chuyển ';' làm dấu phân tách và cắt các chuỗi được trả về.

+0

cảm ơn bạn đã giải thích chi tiết này! –

14

SplitString được định nghĩa là

function SplitString(const S, Delimiters: string): TStringDynArray; 

Người ta sẽ nghĩ rằng Delimiters biểu thị chuỗi delimiter đơn sử dụng cho chuỗi tách, nhưng nó thực sự biểu thị tập hợp các ký tự đơn sử dụng để chia chuỗi. Mỗi ký tự trong chuỗi Delimiters sẽ được sử dụng làm một trong các dấu phân tách có thể có.

SplitString

Tách một chuỗi thành phần khác nhau giới hạn bởi các quy định delimiter ký tự. SplitString tách một chuỗi thành các phần khác nhau được phân tách bằng dấu phân cách được chỉ định ký tự. S là chuỗi được tách ra là . Dấu phân tách là một chuỗi có chứa các ký tự được định nghĩa là dấu phân cách.

+1

Tôi giả sử họ sẽ gọi nó là "Delimiter' (số ít) sau đó, không phải' Delimiters'. FWIW, Trong các phiên bản sau này, 'TStringHelper' có một phiên bản' Tách' cũng có chuỗi như dấu phân tách, không chỉ ký tự, Nhưng tiếc là không có trong XE2. –

+0

@RudyVelthuis Đồng ý. Nhưng ranh giới giữa Delimiter và Delimiters có thể bị mất nếu bạn không phải là người nói tiếng Anh bản địa. Bên cạnh đó, các hoạt động tách trong các ngôn ngữ khác thường hoàn thành, phân cách chính xác được đưa ra để thực hiện Delphi này khá khó hiểu từ khía cạnh đó. –

+0

@RudyVelthuis, Tuy nhiên, Split cũng có một bộ các quirks riêng: http://stackoverflow.com/questions/28410901/string-split-works-strange-when-last-value-is-empty –

5

Đó là do tham số thứ hai của SplitString là danh sách các ký tự phân tách ký tự đơn, vì vậy '; 'có nghĩa là chia thành một'; ' HOẶC chia thành một ''. Vì vậy, chuỗi được chia ở mọi ';' và ở mọi không gian và giữa ';' và '' không có gì, vì thế các chuỗi rỗng.

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