203 00:16:38,731 --> 00:16:41,325 <i>Happy Christmas, your arse I pray God it's our last</i>
- عدم حذف تگها ، گاها برنامه نویسها از تگ هایی چون Bold,italic,underline,color استفاده میکنند که معدود برنامههایی آن را پشتیبانی کرده و تلویزیون و پلیرها هم که اصلا پشتیبانی نمیکنند و باعث میشود که متن روی تلویزیون مثل کد html ظاهر شود
- بعضی جملات دوبار روی صفحه ظاهر میشوند.
- تنها یک فایل را در هر زمان تبدیل میکند. مثلا اگر یک سریال چند قسمته داشته باشید، برای هر قسمت باید زیرنویس را انتخاب کرده و تبدیل کنید، در صورتی که میتوان دستور داد تمام زیرنویسهای داخل دایرکتوری را تبدیل کرد یا چند زیرنویس را برای این منظور انتخاب کرد.
نحوهی خواندن زیرنویس با کدنویسی
203 00:16:38,731 --> 00:16:41,325 <i>Happy Christmas, your arse I pray God it's our last</i>
private readonly static Regex regex_srt = new Regex(@"(?<sequence>\d+)\r\n(?<start>\d{2}\:\d{2}\:\d{2},\d{3}) --\> " + @"(?<end>\d{2}\:\d{2}\:\d{2},\d{3})\r\n(?<text>[\s\S]*?)\r\n\r\n", RegexOptions.Compiled); public string ToUnicode(string lines) { string subtitle= regex_srt.Replace(lines,delegate(Match m) { string text = m.Groups["text"].Value; //1.remove tags text = CleanScriptTags(text); //2.replace letters PersianReshape reshaper = new PersianReshape(); text = reshaper.reshape(text); string[] splitedlines = text.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); text = ""; foreach (string line in splitedlines) { //3.reverse tags text += ReverseText(reshaper.reshape(line))+Environment.NewLine ; } return string.Format("{0}\r\n{1} --> {2}\r\n", m.Groups["sequence"], m.Groups["start"].Value, m.Groups["end"]) + text + Environment.NewLine+Environment.NewLine ; } ); return subtitle; }
m.Groups["text"].Value
private static readonly Regex regex_tags = new Regex("<.*?>", RegexOptions.Compiled); private string CleanScriptTags(string html) { return regex_tags.Replace(html, string.Empty); }
PersianReshape reshaper = new PersianReshape(); text = reshaper.reshape(text); string[] splitedlines = text.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); text = ""; foreach (string line in splitedlines) { //3.reverse tags text += ReverseText(reshaper.reshape(line))+Environment.NewLine ; }
Dictionary<int ,int> letters=new Dictionary<int, int>(); //0=0x0 ,1=1x0 ,2=0x1 ,3=1x1 private void FillPrimaryTable() { //آ letters.Add(1570, 65153); //ا letters.Add(1575, 65166); //أ letters.Add(1571, 65155); //ب letters.Add(1576, 65167); //ت letters.Add(1578, 65173); //ث letters.Add(1579, 65177); //ج letters.Add(1580, 65181); ..... } Dictionary<int,byte> specialchars=new Dictionary<int, byte>(); private void SetSpecialChars() { //آ specialchars.Add(1570, 0); //ا specialchars.Add(1575, 0); //د2 specialchars.Add(1583, 1); //ذ2 specialchars.Add(1584, 1); //ر2 specialchars.Add(1585, 1); //ز2 specialchars.Add(1586, 1); //ژ specialchars.Add(1688, 1); //و2 specialchars.Add(1608, 1); //أ specialchars.Add(1571, 1); }
در آن متد هر بار یک حرف را انتخاب میکرد و حرف قبلی و بعدی آن را ارسال میکرد تا تابع CalculateIncrease آن را محاسبه کرده و کاراکتر نهایی را باز گرداند و به متغیر finalText اضافه میکرد. ولی در حین نوشتن، زمانی را به یاد آوردم که اندروید به تازگی آمده بود و هنوز در آن زمان از زبان فارسی پشتیبانی نمیکرد و حروف برنامههایی که مینوشتیم به صورت جدا از هم بود و همین مشکل را داشت که ما این مشکل را با استفاده از یک کلاس جاوا که دوست عزیزی آن را در اینجا به اشتراک گذاشته بود، حل میکردیم. پس به این صورت بود که از ادامهی نوشتن کلاس انصراف دادم و از یک کلاس دقیقتر و آماده استفاده کردم.
PersianReshape reshaper = new PersianReshape(); text = reshaper.reshape(text);
//3.reverse tags text = ReverseText(text);
string[] splitedlines = text.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); text = ""; foreach (string line in splitedlines) { //3.reverse tags text += ReverseText(reshaper.reshape(line))+Environment.NewLine ; }
private string Reverse(string text) { return Reverse(text,0,text.Length); } private string Reverse(string text,int start,int end) { if (end < start) return text; string reverseText = ""; for (int i = end-1; i >=start; i--) { reverseText += text[i]; } return reverseText; }
private string ReverseText(string text) { char[] chararray = text.ToCharArray(); string reverseText = ""; bool prefixcomp = false; bool postfixcomp = false; string prefix = ""; string postfix = ""; #region get prefix symbols for (int i = 0; i < chararray.Length; i++) { if (!prefixcomp) { char ch =(char) chararray.GetValue(i) ; if (ch< 130) { prefix += chararray.GetValue(i); } else { prefixcomp = true; break; } } } #endregion }
#region get postfix symbols for (int i = chararray.Length - 1; i >-1 ; i--) { if (!postfixcomp && prefix.Length!=text.Length) { char ch = (char)chararray.GetValue(i); if (ch < 130) { postfix += chararray.GetValue(i); } else { postfixcomp = true; break; } } } #endregion
#region reverse text reverseText = Reverse(text, prefix.Length, text.Length-postfix.Length); reverseText = unTagetdLettersRegex.Replace(reverseText, delegate(Match m) { return Reverse(m.Value); }); #endregion
private static readonly Regex unTagetdLettersRegex = new Regex(@"[A-Za-z0-9]+", RegexOptions.Compiled);
return prefix+ reverseText+postfix;
private static readonly Regex unTagetdLettersRegex = new Regex(@"[A-Za-z0-9]+", RegexOptions.Compiled); private string ReverseText(string text) { char[] chararray = text.ToCharArray(); string reverseText = ""; bool prefixcomp = false; bool postfixcomp = false; string prefix = ""; string postfix = ""; #region get prefix symbols for (int i = 0; i < chararray.Length; i++) { if (!prefixcomp) { char ch =(char) chararray.GetValue(i) ; if (ch< 130) { prefix += chararray.GetValue(i); } else { prefixcomp = true; break; } } } #endregion #region get postfix symbols for (int i = chararray.Length - 1; i >-1 ; i--) { if (!postfixcomp && prefix.Length!=text.Length) { char ch = (char)chararray.GetValue(i); if (ch < 130) { postfix += chararray.GetValue(i); } else { postfixcomp = true; break; } } } #endregion #region reverse text reverseText = Reverse(text, prefix.Length, text.Length-postfix.Length); reverseText = unTagetdLettersRegex.Replace(reverseText, delegate(Match m) { return Reverse(m.Value); }); #endregion return prefix+ reverseText+postfix; }
return string.Format("{0}\r\n{1} --> {2}\r\n", m.Groups["sequence"], m.Groups["start"].Value, m.Groups["end"]) + text + Environment.NewLine+Environment.NewLine ;
نمایی از برنامهی نهایی
روی پلیر یا تلویزیون
نکتهی نهایی: هنگام تست زیرنویس روی فیلم متوجه شدم پلیر خطوط بلند را که در صفحهی نمایش جا نمیشود، میشکند و به دو خط تقسیم میکند. ولی نکتهی خنده دار اینجا بود که خط اول را پایین میاندازد و خط دوم را بالا. برای همین این تکه کد را نوشتم و به طور جداگانه در گیت هاب هم قرار دادهام.
این تکه کد را هم بعد از
//1.remove tags text = CleanScriptTags(text);
text =StringUtils.ConvertToMultiLine(text);
کد متد ConvertToMultiline:
namespace Utils { public static class StringUtils { public static string ConvertToMultiLine(String text, int min = 30, int max = 40) { if (text.Trim() == "") return text; string[] words = text.Split(new string[] { " " }, StringSplitOptions.None); string text1 = ""; string text2 = ""; foreach (string w in words) { if (text1.Length < min) { if (text1.Length == 0) { text1 = w; continue; } if (w.Length + text1.Length <= max) text1 += " " + w; } else text2 += w + " "; } text1 = text1.Trim(); text2 = text2.Trim(); if (text2.Length > 0) { text1 += Environment.NewLine + ConvertToMultiLine(text2, min, max); } return text1; } } }
برنامه مورد نظر را به طور کامل میتوانید از اینجا یا اینجا به صورت فایل نهایی و هم سورس دریافت کنید.