Subtitle Parseleme-[ÇÖZÜLDÜ]

Delphi'de kod yazma ile ilgili sorularınızı bu foruma yazabilirsiniz.
Cevapla
Kullanıcı avatarı
AliZairov
Üye
Mesajlar: 341
Kayıt: 06 Nis 2012 03:09
Konum: Azerbaycan, Bakü
İletişim:

Subtitle Parseleme-[ÇÖZÜLDÜ]

Mesaj gönderen AliZairov »

Merhaba. Subtitle Parse yaparak metinleri sese çevirceğim. Şöyle bir örneğim var.

Kod: Tümünü seç

1
00:00:08,570 --> 00:00:11,090
Her yerde oynar

2
00:00:12,330 --> 00:00:14,230
Ve her zaman

3
00:00:14,650 --> 00:00:17,500
Bulutta barındırılan

4
00:00:17,800 --> 00:00:20,650
Her zaman güncel

5
00:00:21,550 --> 00:00:24,400
İzleyiciler için büyük bir deneyim oluşturmak

6
00:00:25,400 --> 00:00:27,800
Analitik aracılığıyla izleyici istatistikleri

7
00:00:28,500 --> 00:00:30,350
Video için yerleşik reklam teknolojisi

8
00:00:35,500 --> 00:00:37,880
Video için tutku ile oluşturulan
Bende parselemek için şöyle bir api yazıyorum daha kolay olsun diye.

Kod: Tümünü seç

unit SubApi;

interface

uses
  System.SysUtils;

type
  TInfo = Record
    StartTime: string;
    EndTime: string;
    Text: string;
  end;

type
  TSubObject = class (TObject)
  private
    function GetItems(Index: Integer): TInfo;
  public
    Source: string;
    function GetCount: Integer;
    property Items[Index: Integer]: TInfo read GetItems;
  end;

implementation

{ TSubObject }

function TSubObject.GetCount: Integer;
var
  I: Integer;
begin
  I := 0;
  while Pos('-->', Source) > 0 do
  begin
    inc(I);
    Delete(Source, 1, Pos('-->', Source));
  end;
  Result := I;
end;

function TSubObject.GetItems(Index: Integer): TInfo;
var
  Info: TInfo;
begin
  Info.StartTime := '';
  Info.EndTime := '';
  Info.Text := '';
  Result := Info;
end;

end.
Kullanımında böyle düşündüm

Kod: Tümünü seç

procedure TMain.Button1Click(Sender: TObject);
var
  Sub: TSubObject; // uses SubApi
begin
  Sub := TSubObject.Create;
  Sub.Source := Memo1.Text;
  ShowMessage(Sub.Items[1].Text); // Burda index verilenin bilgisin almak
end;
Bu bilgileri girilen index göre almak istiyorum amma yapamadım.
En son AliZairov tarafından 07 Ağu 2015 04:17 tarihinde düzenlendi, toplamda 1 kere düzenlendi.
Kullanıcı avatarı
SimaWB
Üye
Mesajlar: 1316
Kayıt: 07 May 2009 10:42
Konum: İstanbul
İletişim:

Re: Subtitle Parseleme

Mesaj gönderen SimaWB »

Alt yazı için verilen örneğe bakarsak her 4 satırda bir yeni blok var gibi kabul edilebilir.
TSubObject sınıfı Create edilirken tüm alt yazılar ona geçirilip ardından istenilen index'teki bilgilere ulaşmak için ben olsan şöyle bir yol denerdim:

Kod: Tümünü seç

  TSubObject = class (TObject)
  private
    fLines: TStringList;
    function GetItems(Index: Integer): TInfo;
  public
    constructor Create(Lines: TStringList);
    destructor Destroy; override;
    property Items[Index: Integer]: TInfo read GetItems;
  end;

Kod: Tümünü seç

{ TSubObject }
constructor TSubObject.Create(Lines: TStringList);
begin
  fLines := TStringList.Create;
  fLines.Text := Lines.Text;
end;

destructor TSubObject.Destroy;
begin
  fLines.Free;
  inherited;
end;

function TSubObject.GetItems(Index: Integer): TInfo;
var
  Info: TInfo;
  BlokSayisi, p: Integer;
  satir: string;
begin
  Info.StartTime := '';
  Info.EndTime := '';
  Info.Text := '';
  if fLines.Count > 0 then
  begin
    BlokSayisi := (fLines.Count div 4) + 1; // Her 4 satır bir blok
    if Index <= BlokSayisi then
    begin
      satir := fLines[(Index-1)*4+1];
      p := Pos('-->', satir);
      if p > 0 then
      begin
        Info.StartTime := Copy(satir, 1, p-2);
        Info.EndTime   := Copy(satir, p+4, 1000);
        Info.Text      := fLines[(Index-1)*4+2]
      end;
    end;
  end;

  Result := Info;
end;
Kullanımı:

Kod: Tümünü seç

var
  SubObj: TSubObject;
  ti: TInfo;
begin
  SubObj := TSubObject.Create(TStringList(Memo1.Lines));
  try
    ti := SubObj.Items[3];
  finally
    SubObj.Free;
  end;
end;
There's no place like 127.0.0.1
Kullanıcı avatarı
AliZairov
Üye
Mesajlar: 341
Kayıt: 06 Nis 2012 03:09
Konum: Azerbaycan, Bakü
İletişim:

Re: Subtitle Parseleme

Mesaj gönderen AliZairov »

Merhaba. Çok teşekkür ederim. Elinize sağlık. Bu benim aklıma hiç gelmemişti.

Gerçek bir alt yazı ile denedim amma bu defa 4 olmadığından boş geldi veri.

Kod: Tümünü seç

1
00:00:34,952 --> 00:00:38,413
<i>Acilen görev yerlerinize gidin.
Bu bir tatbikat değildir.</i>

2
00:00:38,455 --> 00:00:40,249
<i>Saldırı altındayız.</i>

3
00:00:41,291 --> 00:00:43,085
<i>Saldırı altındayız.</i>

4
00:01:43,812 --> 00:01:46,231
- Lanet olsun!
- Laflarımıza dikkat edelim.

5
00:01:46,273 --> 00:01:48,400
Jarvis, yukarıdan vaziyet ne durumda?

6
00:01:48,442 --> 00:01:51,612
<i>Merkezi bina bir tür
enerji kalkanıyla korunuyor.</i>

7
00:01:52,112 --> 00:01:55,765
<i>Strucker'ın teknolojisi şu ana kadar zapt
ettiğimiz bütün Hydra üslerinin ilerisinde.</i>
Kullanıcı avatarı
AliZairov
Üye
Mesajlar: 341
Kayıt: 06 Nis 2012 03:09
Konum: Azerbaycan, Bakü
İletişim:

Re: Subtitle Parseleme

Mesaj gönderen AliZairov »

Merhaba. Konu güncel.
Kullanıcı avatarı
SimaWB
Üye
Mesajlar: 1316
Kayıt: 07 May 2009 10:42
Konum: İstanbul
İletişim:

Re: Subtitle Parseleme

Mesaj gönderen SimaWB »

Keşke soruyu ilk sorduğunuzda daha detaylı bilgi verseydiniz.
Farklı farklı alternatifler için farklı çözümler verilmesini beklemeyin bence. Size yol göstermesi açısından bir örnek verilmiş. Cevaplar genelde size yol göstermeli, direk çözüm olmamalı.

Verdiğiniz son örneğe göre ilk aklıma gelen çözüm:
Sadece sayı olan satıları bulup ondan sonraki ilk boş satıra kadar(yada dosya sonuna kadar) olan kısmı bir blok kabul etmek.
There's no place like 127.0.0.1
akdatilla
Üye
Mesajlar: 292
Kayıt: 02 Nis 2006 06:04
Konum: Antalya

Re: Subtitle Parseleme

Mesaj gönderen akdatilla »

Merhaba, kod örneği veremeyeceğim ancak şu şekilde yapabilirsin bence.
Dosya örneğine baktığımızda,
Dosya başından itibaren ilk olarak 1 tamsayı bulmalısın. Görünüşe göre 1.satırda tamsayı var ancak yine de bir döngü ie teyit etmen iyi olur.
Bulduğun tamsayı kayıt numarası sayılır.
Kayıt numarasının ardında 1 satırlık saat bilgisi bulunuyor.
Daha sonra ilk boş satırı görünceye kadar text bilgisi olarak alınmalı.
Bu tarife göre bir döngü içerisinde bütün kayıtlar okunarak belleğe yüklenmeli.
Kolay gelsin
Kullanıcı avatarı
AliZairov
Üye
Mesajlar: 341
Kayıt: 06 Nis 2012 03:09
Konum: Azerbaycan, Bakü
İletişim:

Re: Subtitle Parseleme

Mesaj gönderen AliZairov »

Merhaba. Teşekkürler. sıra numarası ve boşuk almağı düşünüyorum. Son satırada boşluk yok kendim ekleyeceğim sorun olmasın diye.
Kullanıcı avatarı
mrmarman
Üye
Mesajlar: 4740
Kayıt: 09 Ara 2003 08:13
Konum: İstanbul
İletişim:

Re: Subtitle Parseleme

Mesaj gönderen mrmarman »

DivXTurk günlerim aklıma geldi.. :)
İşlemi anahtar satır olan --> üzerinden yürürseniz sıkıntı kalmaz.

API Unit

Kod: Tümünü seç

unit SubApi;

interface

uses
  SysUtils, Classes;

type
  tInfo = Record
    idx       : Integer;
    StartTime : string;
    EndTime   : string;
    Text      : string;
end;

  tSubObject = class (TObject)
  private
    fLines    : TStringList;
    function    GetItems(Index: Integer): TInfo;
  public
    constructor Create(Lines: TStringList);
    destructor  Destroy; override;
    property    Items[Index: Integer]: TInfo read GetItems;
  end;

implementation

{ TSubObject }
constructor TSubObject.Create(Lines: TStringList);
begin
  fLines      := TStringList.Create;
  fLines.Text := Lines.Text;
end;

destructor TSubObject.Destroy;
begin
  fLines.Free;
  inherited;
end;

function TSubObject.GetItems(Index: Integer): TInfo;
var
  Info  : TInfo;
  strSat, strAra : String;
  iSat  : Integer;
begin
  FillChar( Result, SizeOf(Result), 0 );
  Result.idx := -1; // varsayılan değer (-1)
  if fLines.Count = 0 then Exit;

  iSat := 0;
  while (iSat < fLines.Count) AND (Result.idx <> Index) do
  begin
    // Anahtar Satırımız TimeCode Satırı...
    while (iSat < fLines.Count)
      AND (Pos('-->', fLines[iSat]) <= 0)
        do inc(iSat);

    // !! Kontrol!! //
    if iSat >= fLines.Count then Exit;

  // TimeCode varsa bir önceki satır = Index...
    dec(iSat);
    if Index = StrToInt( Trim(fLines[iSat]) ) then
    begin  // Aranan replik noya ulaşıldı, parse başlasın.
      FillChar( Info, SizeOf(Info), 0 );
      Info.idx := Index;

    // Şimdi TimeCode bilgileri...
      inc(iSat);
      strSat := fLines[iSat];
      strAra := '-->';
      Info.StartTime := Trim(Copy( strSat, 1, Pos(strAra, strSat) -1));
      system.Delete(strSat, 1, Pos(strAra, strSat) + Length(strAra)-1 );
      Info.EndTime   := Trim(strSat);

    // Şimdi Metin bilgileri...
      inc(iSat);
      while (iSat < fLines.Count) AND ( Trim(fLines[iSat]) <> '' ) do
      begin
        Info.Text := Info.Text + Trim(fLines[iSat]) + #13#10;
        inc(iSat);
      end;
      Result := Info;
    end else inc(iSat,2); // index bulunana kadar veya tükenene kadar devam...
  end; // While
end;

end.
Kullanımı :

Kod: Tümünü seç

procedure TForm1.BitBtn1Click(Sender: TObject);
var
  SubObj: TSubObject;
  ti: TInfo;
begin
  SubObj := TSubObject.Create(TStringList(Memo1.Lines));
  try
    ti := SubObj.Items[7];
    if ti.idx <> -1
    then ShowMessageFmt( '%s : %s'#13'%s', [ ti.StartTime, ti.EndTime, ti.Text] );
  finally
    SubObj.Free;
  end;
end;
Resim
Resim ....Resim
Kullanıcı avatarı
AliZairov
Üye
Mesajlar: 341
Kayıt: 06 Nis 2012 03:09
Konum: Azerbaycan, Bakü
İletişim:

Re: Subtitle Parseleme

Mesaj gönderen AliZairov »

Merhaba Muharrem abi. Teşekkürler. Hemen inceliyorum.
Kullanıcı avatarı
AliZairov
Üye
Mesajlar: 341
Kayıt: 06 Nis 2012 03:09
Konum: Azerbaycan, Bakü
İletişim:

Re: Subtitle Parseleme

Mesaj gönderen AliZairov »

Merhaba. Muharrem abi tekrar teşekkürler. Biraz apiyi düzenlemiştim son sürüm böyle daha kolay düşünüyorum.

SubApi.pas

Kod: Tümünü seç

unit SubApi;

interface

uses
  System.SysUtils, System.Classes;

type
  TSubItem = Record
    Index: Integer;
    StartTime: string;
    EndTime: string;
    Text: string;
  end;

type
  TSubObject = class (TObject)
  private
    FList: TStringList;
    function ClearTag(S: string): string;
    function GetItems(Index: Integer): TSubItem;
  public
    constructor Create(Source: string);
    destructor Destroy; override;
    function GetCount: Integer;
    property Items[Index: Integer]: TSubItem read GetItems;
  end;

implementation

{ TSubObject }

function TSubObject.ClearTag(S: string): string;
var
 TagBegin, TagEnd, TagLength: Integer;
begin
 TagBegin := Pos( '<', S);
 while (TagBegin > 0) do begin
  TagEnd := Pos('>', S);
  TagLength := TagEnd - TagBegin + 1;
  Delete(S, TagBegin, TagLength);
  TagBegin:= Pos( '<', S);
 end;
 Result := S;
end;

constructor TSubObject.Create(Source: string);
begin
  inherited Create;
  FList := TStringList.Create;
  FList.Text := Trim(Source);
end;

destructor TSubObject.Destroy;
begin
  FList.Free;
  inherited Destroy;
end;

function TSubObject.GetCount: Integer;
var
  Source: string;
  I: Integer;
begin
  Source := FList.Text;
  I := 0;
  while Pos('-->', Source) > 0 do
  begin
    inc(I);
    Delete(Source, 1, Pos('-->', Source));
  end;
  Result := I;
end;

function TSubObject.GetItems(Index: Integer): TSubItem;
var
  strSat, strAra: String;
  iSat: Integer;
begin
  FillChar( Result, SizeOf(Result), 0 );
  Result.Index := - 1;
  if FList.Count = 0 then Exit;
  iSat := 0;
  while (iSat < FList.Count) AND (Result.Index <> Index) do
  begin
    while (iSat < FList.Count)
      AND (Pos('-->', FList[iSat]) <= 0)
        do inc(iSat);
    if iSat >= FList.Count then Exit;
    dec(iSat);
    if Index = StrToInt( Trim(FList[iSat]) ) then
    begin
      FillChar(Result, SizeOf(Result), 0 );
      Result.Index := Index;
      inc(iSat);
      strSat := FList[iSat];
      strAra := '-->';
      Result.StartTime := Trim(Copy( strSat, 1, Pos(strAra, strSat) -1));
      System.Delete(strSat, 1, Pos(strAra, strSat) + Length(strAra)-1 );
      Result.EndTime   := Trim(strSat);
      inc(iSat);
      while (iSat < FList.Count) AND ( Trim(FList[iSat]) <> '' ) do
      begin
        Result.Text := ClearTag(Result.Text + Trim(FList[iSat]) + #13#10);
        inc(iSat);
      end;
    end else inc(iSat, 2);
  end;
end;

end.
Kullanımı:

Kod: Tümünü seç

var
  Sub: TSubObject; // uses SubApi
  I: Integer;
begin
  Sub := TSubObject.Create(Memo1.Lines.Text);
  // Tek olarak
  Memo2.Lines.Add('StartTime = ' + Sub.Items[1].Text);
  // Dongüde
  for I := 1 to Sub.GetCount do
  begin
    Memo2.Lines.Add('StartTime = ' + Sub.Items[I].StartTime);
    Memo2.Lines.Add('EndTime = ' + Sub.Items[I].EndTime);
    Memo2.Lines.Add('Text = ' + Sub.Items[I].Text);
  end;
Kullanıcı avatarı
mrmarman
Üye
Mesajlar: 4740
Kayıt: 09 Ara 2003 08:13
Konum: İstanbul
İletişim:

Re: Subtitle Parseleme

Mesaj gönderen mrmarman »

Hocam bu şekilde her altyazı satırını almak için tekrar tekrar search ettirmek verimli olmaz.
Sana verdiğim örnek yine de iş görür ama asıl amaç index nosu bilinen bir repliğe ulaşmak içindir. Yani bir yerde SUB, SMI, SRT vs. tüm metin vardır, sen birisine kaynağından yeniden ulaşmak istediğinde index nosuyla başvurursun.

Özetle; tekrar tekrar 1, 1.2, 1.2.3, 1.2.3.4, 1.2.3.4.5, 1.2.3.4.5.6 şeklinde baştan taratarak ola ki 1000 replik olan bir altyazı için 1000 kere döngüyü azalan şekilde kurmak şeklindeki mevcut çalışma verimli olmaz.

Çözüm : Böyle sıralı olarak alacaksan API içindeki eşitlik kontrolünü (hani index = aranan idx ise içeriğini al kısmı ) devre dışı bırakıp tümünü bir batında alabilirsin. Asıl öyle verimli olur.

Ne yaparsın INDEX değeri -1 ise deyip parametre olarak bir de TListBox koyarsın o da NIL değilse içeriği bu TListBox'a TOBJECT sınıfından bir CLASS ile bu type kısmını doldur diyebilirsin.
Resim
Resim ....Resim
Kullanıcı avatarı
AliZairov
Üye
Mesajlar: 341
Kayıt: 06 Nis 2012 03:09
Konum: Azerbaycan, Bakü
İletişim:

Re: Subtitle Parseleme

Mesaj gönderen AliZairov »

Tamam Muharrem abi. Öylede olur. Yaparım öyle.
Cevapla