2013-10-24 3 views
5

में टेक्स्ट को विभाजित करने का तेज़ तरीका मेरे पास एक ऐप है जिसे TStringList में भारी टेक्स्ट मैनिपुलेशन करने की आवश्यकता है। असल में मुझे एक डिलीमीटर द्वारा पाठ को विभाजित करने की आवश्यकता है; उदाहरण के लिए, यदि मेरे पास 1000 वर्णों के साथ एक सिंगल लाइन है और इस लाइन में यह डिलीमीटर 3 बार होता है, तो मुझे इसे 3 लाइनों में विभाजित करने की आवश्यकता होती है। डिलीमीटर में एक से अधिक चार हो सकते हैं, उदाहरण के लिए यह '[test]' जैसा टैग हो सकता है।डेल्फी TStringList

मैंने इस कार्य को 2 अलग-अलग दृष्टिकोणों के साथ करने के लिए दो कार्य लिखे हैं, लेकिन दोनों बड़ी मात्रा में टेक्स्ट (आमतौर पर 2 एमबाइट्स) में धीमे होते हैं।

मैं इस लक्ष्य को तेज़ी से कैसे प्राप्त कर सकता हूं?

यहां दोनों कार्य हैं, दोनों को 2 पैरामीटर प्राप्त होते हैं: 'रेखाएं' जो मूल tstringlist और 'q' है जो delimiter है।

function splitlines(lines : tstringlist; q: string) : integer; 
var 
    s, aux, ant : string; 
    i,j : integer; 
    flag : boolean; 
    m2 : tstringlist; 
begin 
    try 
    m2 := tstringlist.create; 
    m2.BeginUpdate; 
    result := 0; 
    for i := 0 to lines.count-1 do 
    begin 
     s := lines[i]; 
     for j := 1 to length(s) do 
     begin 
     flag := lowercase(copy(s,j,length(q))) = lowercase(q); 
     if flag then 
     begin 
      inc(result); 
      m2.add(aux); 
      aux := s[j]; 
     end 
     else 
      aux := aux + s[j]; 
     end; 
     m2.add(aux); 
     aux := ''; 
    end; 
    m2.EndUpdate; 
    lines.text := m2.text; 
    finally 
    m2.free; 
    end; 
end; 


function splitLines2(lines : tstringlist; q: string) : integer; 
var 
    aux, p : string; 
    i : integer; 
    flag : boolean; 
begin 
    //maux1 and maux2 are already instanced in the parent class 
    try 
    maux2.text := lines.text; 
    p := ''; 
    i := 0; 
    flag := false; 
    maux1.BeginUpdate; 
    maux2.BeginUpdate; 
    while (pos(lowercase(q),lowercase(maux2.text)) > 0) and (i < 5000) do 
    begin 
     flag := true; 
     aux := p+copy(maux2.text,1,pos(lowercase(q),lowercase(maux2.text))-1); 
     maux1.add(aux); 
     maux2.text := copy(maux2.text,pos(lowercase(q),lowercase(maux2.text)),length(maux2.text)); 
     p := copy(maux2.text,1,1); 
     maux2.text := copy(maux2.text,2,length(maux2.text)); 
     inc(i); 
    end; 
    finally 
    result := i; 
    maux1.EndUpdate; 
    maux2.EndUpdate; 
    if flag then 
    begin 
     maux1.add(p+maux2.text); 
     lines.text := maux1.text; 
    end; 
    end; 
end; 
+0

समस्या मेरी सीमांकक एक से अधिक चार है, यह एक पूरे शब्द, उदाहरण के लिए हो सकता है। – delphirules

+3

प्रश्न में सभी आवश्यकताओं को शामिल करें। बीटीडब्ल्यू, कन्स्ट्रक्टर कॉल के बाद कोशिश करें। –

+2

आपको इस प्रश्न का उत्तर देने योग्य मेरा उत्तर मिल सकता है: http://stackoverflow.com/questions/15424293/how-to-split-string-by-a-multi-character-delimiter/15427587#15427587 –

उत्तर

15

मैं गति परीक्षण नहीं किया गया है, लेकिन शैक्षिक उद्देश्यों के लिए है, यहाँ तार विभाजित करने के लिए एक आसान तरीका है:

myStringList.Text := 
    StringReplace(myStringList.Text, myDelimiter, #13#10, [rfReplaceAll]); 
// Use [rfReplaceAll, rfIgnoreCase] if you want to ignore case 

आप TStringList की Text गुण सेट जब , यह नई लाइनों पर विभाजित होता है और वहां विभाजित होता है, इसलिए एक स्ट्रिंग में कनवर्ट करना, डिलीमीटर को नई लाइनों के साथ बदलना, फिर उसे Text संपत्ति कार्यों पर वापस असाइन करना।

+0

मैन, हमेशा के लिए धन्यवाद ! आपने अभी अपना ऐप बहुत बेहतर बनाया है! : डी – delphirules

+2

Couoolest विचार! +1 –

+0

@ मर्कस एडम्स आईआईआरसी, यूनिकोड डेल्फी में स्ट्रिंगरप्लेस (यानी फास्टकोड-सक्षम नहीं) बहुत धीमी है जब स्ट्रिंग का आकार कई मेगा बाइट्स से बड़ा हो जाता है। – SOUser

0

सिर्फ

प्रक्रिया StrTokens (स्थिरांक एस: स्ट्रिंग; स्थिरांक सूची: TStrings) JCL पुस्तकालय से StrTokens उपयोग के बारे में कैसे;

यह ओपन सोर्स http://sourceforge.net/projects/jcl/

2

अपने कोड के साथ समस्याओं (कम से कम दूसरा दृष्टिकोण)

  • आप लगातार lowecase जो धीमी है यदि ऐसा है तो कई बार
  • कहा जाता है, तो मैंने देखा कि सही ढंग से आप पूरे शेष पाठ वापस कॉपी कर रहे हैं का उपयोग कर रहे हैं मूल स्रोत के लिए। यह सुनिश्चित है कि बड़े तारों (उदाहरण के लिए फाइलें)

मेरे पुस्तकालय में टोकननाइज़र है। इसके नहीं सबसे तेजी से या सबसे अच्छा है, लेकिन यह क्या करना चाहिए (आप इसे Cromis Library से प्राप्त कर सकते हैं, बस इकाइयों Cromis.StringUtils और Cromis.Unicode का उपयोग करें):

type 
    TTokens = array of ustring; 

    TTextTokenizer = class 
    private 
    FTokens: TTokens; 
    FDelimiters: array of ustring; 
    public 
    constructor Create; 
    procedure Tokenize(const Text: ustring); 
    procedure AddDelimiters(const Delimiters: array of ustring); 
    property Tokens: TTokens read FTokens; 
    end; 

{ TTextTokenizer } 

procedure TTextTokenizer.AddDelimiters(const Delimiters: array of ustring); 
var 
    I: Integer; 
begin 
    if Length(Delimiters) > 0 then 
    begin 
    SetLength(FDelimiters, Length(Delimiters)); 

    for I := 0 to Length(Delimiters) - 1 do 
     FDelimiters[I] := Delimiters[I]; 
    end; 
end; 

constructor TTextTokenizer.Create; 
begin 
    SetLength(FTokens, 0); 
    SetLength(FDelimiters, 0); 
end; 

procedure TTextTokenizer.Tokenize(const Text: ustring); 
var 
    I, K: Integer; 
    Counter: Integer; 
    NewToken: ustring; 
    Position: Integer; 
    CurrToken: ustring; 
begin 
    SetLength(FTokens, 100); 
    CurrToken := ''; 
    Counter := 0; 

    for I := 1 to Length(Text) do 
    begin 
    CurrToken := CurrToken + Text[I]; 

    for K := 0 to Length(FDelimiters) - 1 do 
    begin 
     Position := Pos(FDelimiters[K], CurrToken); 

     if Position > 0 then 
     begin 
     NewToken := Copy(CurrToken, 1, Position - 1); 

     if NewToken <> '' then 
     begin 
      if Counter > Length(FTokens) then 
      SetLength(FTokens, Length(FTokens) * 2); 

      FTokens[Counter] := Trim(NewToken); 
      Inc(Counter) 
     end; 

     CurrToken := ''; 
     end; 
    end; 
    end; 

    if CurrToken <> '' then 
    begin 
    if Counter > Length(FTokens) then 
     SetLength(FTokens, Length(FTokens) * 2); 

    FTokens[Counter] := Trim(CurrToken); 
    Inc(Counter) 
    end; 

    SetLength(FTokens, Counter); 
end; 
0

एक अतिरिक्त विकल्प के रूप में, आप रेगुलर एक्सप्रेशन का उपयोग कर सकते हैं। डेल्फी (एक्सई 4 और एक्सई 5) के हाल के संस्करण नियमित अभिव्यक्ति समर्थन में निर्मित के साथ आते हैं; पुराने संस्करण पर Regular-Expressions.info पर एक मुफ्त regex library download (zip file) पा सकते हैं।

के लिए निर्मित regex समर्थन (सामान्य TArray<string> उपयोग करता है):

var 
    RegexObj: TRegEx; 
    SplitArray: TArray<string>; 
begin 
    SplitArray := nil; 
    try 
    RegexObj := TRegEx.Create('\[test\]'); // Your sample expression. Replace with q 
    SplitArray := RegexObj.Split(Lines, 0); 
    except 
    on E: ERegularExpressionError do begin 
    // Syntax error in the regular expression 
    end; 
    end; 
    // Use SplitArray 
end; 

पहले डेल्फी संस्करणों में TPerlRegEx का उपयोग कर के लिए:

var 
    Regex: TPerlRegEx; 
    m2: TStringList; 
begin 
    m2 := TStringList.Create; 
    try 
    Regex := TPerlRegEx.Create; 
    try 
     Regex.RegEx := '\[test\]'; // Using your sample expression - replace with q 
     Regex.Options := []; 
     Regex.State := [preNotEmpty]; 
     Regex.Subject := Lines.Text; 
     Regex.SplitCapture(m2, 0); 
    finally 
     Regex.Free; 
    end; 
    // Work with m2 
    finally 
    m2.Free; 
    end; 
end; 

(उन अनजान के लिए, नमूना में \ अभिव्यक्ति का उपयोग इसलिए किया जाता है क्योंकि [] वर्ण नियमित अभिव्यक्तियों में सार्थक हैं और नियमित अभिव्यक्ति पाठ में उपयोग किए जाने से बचने की आवश्यकता है। आमतौर पर, उन्हें पाठ में आवश्यक नहीं है।)

संबंधित मुद्दे