(原創)C# LRC複讀機-1

來源:互聯網
上載者:User

最近想惡補下英語,找了很多MP3播放軟體,但是沒有哪個能按照句子播放時間來播放聲音的,想想自己學習過的WinForm,為什麼不自己寫一個程式呢?一個想法出現在腦海中,說幹就幹,花了一天時間,先研究了一下LRC檔案的結構,windows media player控制項的使用,加上一些簡單的控制,這個簡陋的LRC複讀機就誕生了!在網上得到很多朋友的協助,現將全部來源程式公開,以表謝意,您可以隨意使用,修改.如果程式造成了死機及至電腦起火爆炸,很抱歉,不是我啟動並執行!

代碼很簡單,思路那就更簡單,有句英文怎麼說呢:it’s ugly, it’s simple, but it works!

這個複讀機功能如下:

     可以播放帶有lrc檔案的mp3檔案,按照每個句子的的時間來進行聲音片段的播放.

使用方法:

先點擊選擇檔案,選擇一個有配套LRC的mp3,注意檔案名稱必須相同,不然程式會報錯

然後,程式就會自動載入LRC檔案,並將常值內容讀取到右邊的listBox中,你可以在listBox中雙擊,鍵盤上下,斷行符號什麼的隨便你,總之,想聽哪句點哪句,讀完就暫停了.或者你將英文顯示關掉,只用上一句和下一句控制朗讀,覺得一句一句聽得不過癮,就點全部播放,相信到這兒你看出來了,這個小軟體就是用來練習聽力的

 

要開發,先研究最基本的東西,這個小軟體需要用到lrc,為什麼用它呢?

先說說LRC檔案的結構:

比如這個新概念的一個MP3的LRC檔案內容

 

[al:新概念英語(二)]
[ar:MP3 同步字幕版(美音)]
[ti:A Private Conversation]
[by:更多學習內容,請到VeryCD.com搜尋“露珠”]
[00:09.77]Why did the writer complain to the people behind him?
[00:15.91]Last week I went to the theatre.
[00:19.39]I had a very good seat.
[00:22.07]The play was very interesting.
[00:25.10]I did not enjoy it.
[00:27.43]A young man and a young woman were sitting behind me.
[00:31.96]They were talking loudly.
[00:34.59]I got very angry.
[00:37.41]I could not hear the actors.
[00:40.64]I turned round.
[00:42.80]I looked at the man and the woman angrily.
[00:47.27]They did not pay any attention.
[00:50.69]In the end, I could not bear it.
[00:54.98]I turned round again.
[00:57.75]'I can't hear a word!' I said angrily.
[01:03.45]'It's none of your business,'
[01:06.27]the young man said rudely.
[01:09.00]'This is a private conversation!'

 

前四行不用看,咱們關心的是下面,[]內部就是時間了,比如第一行[00:09.77]表示從09.77秒開始,在下面一句的15.91秒處結束;

[00:15.91]Last week I went to the theatre.這行從15.91秒處開始,在下面一句19.39秒處結束,下面的都一樣,最後一句

[01:09.00]'This is a private conversation!'從1分9秒開始,結束時間?mp3播放的結束時間

 

現在的問題是:如何取得時間以及文本的內容呢?

先說時間,全部都是分鐘在前,秒在後,格式都一樣[??:??.??],這種非常規律的文本用Regex來取值是最簡單不過了,如果你還不懂Regex,請先去學習了再繼續往下看:

/d{2}:/d{2}./d{2}就可以得到整個時間字串,把全部的時間取出來,再做成時間對,比如

00:09.77    00:15.91

00:15.91    00:19.39

以開始時間和結束時間命名,這樣就可以用一個struct來儲存每一對:

struct 時間對    {        public double 開始時間;        public double 結束時間;        //如果想在listBox中顯示開始時間和結束時間,需要重載ToString方法        public override string ToString()        {            return string.Format("{0,8}-{1,8}", 開始時間, 結束時間);        }    }

有了時間對,咱們不就可以在WMP中按照某一段時間來播放了?在WMP的研究中發現要想在WMP中從09.77秒處播放,需要使用double資料類型!

如所示Ctlcontrols.currentPosition只接受double,這個double和時間是個什麼關係?網上沒有找到相關的資料,只好自己做實驗來研究了,弄了個mp3,給這個currentPosition賦值,發現其實很簡單,就是個秒數,比如currentPosition=09.77,播放條一下就跑到09.77秒處了;那麼1分9秒呢?1*60+9,OK,知道如何來控制播放的時間了,講這些是因為需要將01:09.00這種字串轉換成double類型,需要單獨取出分鐘01和秒數09.00,奈何?

Regex可以從一個匹配字串中一次取出二個,上面的/d{2}:/d{2}./d{2},改成(/d{2}):(/d{2}./d{2})就可以了,然後在程式中取出這二組,轉換成double即可:

private static double 擷取匹配時間(string 內容來源){    Regex 時間匹配 = new Regex("(//d{2}):(//d{2}.//d{2})", RegexOptions.None);    if (時間匹配.IsMatch(內容來源))    {        Match ma = 時間匹配.Match(內容來源);        double 分鐘 = Convert.ToDouble(ma.Groups[1].Value);        double 秒數 = Convert.ToDouble(ma.Groups[2].Value);        return 分鐘 * 60 + 秒數;    }    else    {        return -1;    }}

有了能夠取出一個字串中的時間的方法,再使用一個File.ReadAllLines將lrc檔案的每一行都讀取進一個string[]中,弄一個迴圈就可以得到整個lrc檔案的時間對:

public List時間對> 得到時間對列表()        {            List時間對> 時間對列表 = new List時間對>();            時間對 coupleTime = new 時間對();            //讀取LRC檔案的每一行並擷取時間            for (int i = 0; i if (擷取匹配時間(LRC檔案內容[i]) //沒有找到匹配項,繼續                {                    continue;                }                else                {                    coupleTime.開始時間 = 擷取匹配時間(LRC檔案內容[i]);                    coupleTime.結束時間 = 擷取匹配時間(LRC檔案內容[i + 1]);                    時間對列表.Add(coupleTime);                }            }            //最後一個結束時間需要用MP3的總長度賦值,或者偷懶,double.MaxValue:)            coupleTime.開始時間 = 擷取匹配時間(LRC檔案內容[LRC檔案內容.Length - 1]);            coupleTime.結束時間 = double.MaxValue;            時間對列表.Add(coupleTime);            return 時間對列表;        }OK,時間的問題解決掉;常值內容如何得到呢?其實也可以和時間一起擷取,效率高,不過考慮到Regex不好寫,再加上反正lrc檔案小,現在電腦速度快,用簡單清晰略帶冗餘的方式來處理好嘍:
 
private static string 擷取匹配英文短語(string 內容來源){    //注意,如果正則是[a-zA-Z/s/./?'!,]+$,也就是沒有兩邊的()    //那麼取的值就是空,因為並沒有組存在!    //要使用Groups來擷取,必須在兩邊加上()    //Regex 文字匹配 = new Regex(@"([a-zA-Z/d/s/./?'!,_-]+$)", RegexOptions.None);    string 純英文LRC=@"([a-zA-Z/s/./?'’!,,_/d-]+$)";    string 中英文LRC=@"";//留一個位置,以後還可以讀取帶中文翻譯的LRC    string regexString=純英文LRC+中英文LRC;    Regex 文字匹配 = new Regex(regexString, RegexOptions.Multiline);    if (文字匹配.IsMatch(內容來源))    {        Match ma = 文字匹配.Match(內容來源);        return string.IsNullOrEmpty(ma.Groups[1].Value) ? ma.Groups[2].Value : ma.Groups[1].Value;    }    else    {        return null;    }    //這樣也可以得到正確的值    //Regex 文字匹配 = new Regex(@"[a-zA-Z/s/./?'!,]+$", RegexOptions.None);    //if (文字匹配.IsMatch(內容來源))    //{    //    Match ma = 文字匹配.Match(內容來源);    //    return ma.Value;    //}    //else    //{    //    return null;    //}}

這個擷取有一點兒小小問題,就是只能擷取到僅僅含有英文的lrc檔案,如果有中文,那麼就只會得到null,因為Regex([a-zA-Z/d/s/./?'!,_-]+$)最後是以$結束的.

比如這種lrc檔案:

[00:00.440]--- lesson1 SCHOOLS AND EDUCATION 學校和教育

[00:06.160]--- Basic Patterns 基本句型

[00:09.160]What college should I attend in the fall?^秋季我上哪一所大學好呢?

[00:14.080]I’m majoring in history.^我學的是曆史專業。

[00:17.880]Can you tell me where is the dormitory?^你能告訴我宿舍在哪嗎?

[00:22.240]I’m taking extra classes this semester.^這個學期我額外選修了一些課程。

[00:26.720]Are you having problems with chemistry?^你在化學方面有困難嗎?

[00:30.760]I’m not worried about this test.^我並不擔心這次考試。

[00:34.520]The prices on textbooks have gone up.^課本的價格上漲了。

[00:38.880]Our class has a meeting after lunch.^午餐後我們班要開一個會議。

英文字串就擷取不到了,因為最後結束的是中文字元,有非常懂Regex的還請賜教,如何從上面的字串中一次性取得英文字串和中文字串呢?我自己研究了一下,這個英文標點和中文標點可真是讓人頭大,少寫一個或者寫錯,什麼也得不到!

待續...

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.