Tags:
Forums: 

ผมมีไฟล์ประมาณ 40,000 ไฟล์ โดยชื่อไฟล์
best_H1_M1_S1.out
best_H1_M1_S1.out
.
.
.
best_H1_M400_S10.out

โดยชื่อไฟล์ถูกเก็บเป็น list ไว้ในไฟล์ชื่อ filelists.txt
แต่ผมต้องการให้โปรแกรมอ่านชื่อไฟล์เมื่อเจอ _H, _M, _S ให้เอาตัวเลขข้างหลังมาครับ
ผลลัพธ์จะได้ประมาณนี้
H = 1,2,3,4,5
M = 2,2,2,2,2
S = 3,4,5,6,7
ขอคำแนะนำด้วยครับ
ขอบคุณครับ

Get latest news from Blognone
By: itpcc
ContributoriPhoneRed HatUbuntu
on 22 November 2012 - 15:51 #509746
itpcc's picture

ถ้าเป็น php นะ

  • trim เอา best_ ออกก่อน
  • ใช้ explode แตกออกมาเป็นอาเรย์
  • ใช้ intval หรือ substr ตัดเอาเฉพาะตัวเลข
  • สุดท้ายก็เก็บไว้ในอาเรย์ชุดหนึ่ง หรือจะ echo ออกมาเลยก็ได้ครับ

ซับซ้อนนิดนึง แต่คงจะใช้ได้นะครับ ท่านผู้รู้ที่มีความคิดเจ๋งกว่าก็แนะนำดูนะครับ ^^

code คงประมาณนี้

<?php
    $file="filelists.txt";
    $hour=$min=$sec=array();
    $file_array=file($file);//อ่านไฟล์เข้ามา
    $i = 0;
    foreach ($file_array as $line) {//อ่านทีละบรรทัด
        //best_H1_M1_S1.out
        list($hour[$i],$min[$i],$sec[$i]) = explode('_', substr($line,5));//เอา best_ ออก แล้วแตกเป็นอาเรย์
    $hour[$i] = intval(substr($hour[$i],1));
    $min[$i] = intval(substr($min[$i],1));
    $sec[$i] = intval(substr($sec[$i],1,-4));

        $i++;
    }
    unset($file_array);  //ล้างที่คืน จะได้ไม่เป็นภาระของลูกหลาน...
    echo 'H = '; echo implode(',', $hour); echo '\n';
    echo 'M = '; echo implode(',', $min); echo '\n';
    echo 'S = '; echo implode(',', $sec); echo '\n';
    unset($hour); unset($min); unset($sec); //ล้างที่คืน จะได้ไม่เป็นภาระของลูกหลาน...
?>

ปล.เพิ่มการ substr เข้ามาครับ เพิ่งเห็น -_-"


บล็อกส่วนตัวที่อัพเดตตามอารมณ์และความขยัน :P

By: EThaiZone
ContributorAndroidUbuntuWindows
on 22 November 2012 - 14:43 #509838
EThaiZone's picture

{syntaxhighlighter PHP}<?php $file="filelists.txt"; $hour=$min=$sec=array(); $file_array=file($file);//อ่านไฟล์เข้ามา foreach ($file_array as $line) {//อ่านทีละบรรทัด //best_H1_M1_S1.out if(preg_match('#best_H([0-9]+)_M([0-9]+)_S([0-9]+)#', $line, $matches)) { //print_r($matches); $hour[] = $matches[1]; $min[] = $matches[2]; $sec[] = $matches[3]; } } unset($file_array); //ล้างที่คืน จะได้ไม่เป็นภาระของลูกหลาน... echo 'H = '.implode(',', $hour).'\n'; echo 'M = '.implode(',', $min).'\n'; echo 'S = '.implode(',', $sec).'\n'; unset($hour); unset($min); unset($sec); //ล้างที่คืน จะได้ไม่เป็นภาระของลูกหลาน... ?>{/syntaxhighlighter}

มั่นใจว่า regex เขียนไม่ผิด แต่หวังว่า $matches ผมจะเขียนอ้างอิงถูก ถ้าใช่ไม่ได้ลองเอาคอมเมนต์ print_r ออกดูค่าเองละกัน


มันไม่ง่ายเลยที่จะทำ GIF ให้มีขนาดน้อยกว่า 20kB

By: itpcc
ContributoriPhoneRed HatUbuntu
on 22 November 2012 - 15:29 #509861 Reply to:509838
itpcc's picture

Array ( [0] => best_H1_M1_S400 [1] => 1 [2] => 1 [3] => 400 )

อา... นี่ผมเพิ่งรู้จักกับ preg_match ไม่นึกว่ามันจะทำอย่างนี้ได้

และก็เรื่องอาเรย์ทบไปได้เรื่อยๆด้วย

ว่าแต่ว่า การใช้ regular expression ไม่ทำให้ช้าลงเมื่อทำงานกับงานขนาดใหญ่เหรอครับ?


บล็อกส่วนตัวที่อัพเดตตามอารมณ์และความขยัน :P

By: EThaiZone
ContributorAndroidUbuntuWindows
on 22 November 2012 - 16:11 #509887 Reply to:509861
EThaiZone's picture

regex จะช้าลงกับ data ขนาดใหญ่ครับ ถ้ามีการซอยเป็น array ก็ถือว่าไวขึ้นหน่อย
จริงๆ ผมสามารถเขียนให้สั้นกว่านี้ด้วย preg_match_all แต่มันก็จะช้าลงอีก
ถ้าเทียบกับแบบที่คุณเขียนมา ยอมรับว่าของผมช้ากว่า แต่ช้าในระดับมิลลิวินาที

แต่ถามกับงานขนาดใหญ่ ผมยังว่าคุ้มที่จะใช้ เพราะการเขียนแยกเทียบดิบๆ ลองมองว่าถ้า string ที่ใช้ค้นไม่ได้ขึ้นต้นด้วยคำว่า best คำนี้ขนาดไม่ตายตัว พอเทียบกับการปรับโค้ดแล้ว มันเสียเวลาตรงนี้เยอะกว่าครับ

แล้วยังมีกรณีที่เราสามารถใช้วิธีอื่นช่วยเพิ่มความเร็วได้ เช่น การเก็บแคชหลังการ parse ข้อมูลแล้ว โดยอิงการเปลี่ยนแปลงของตัว filelists.txt เอง ซึ่งเราไม่มีความจำเป็นต้อง parse ทุกครั้งที่ request แต่ parse เมื่อ filelists.txt มันไม่เหมือนเดิมก็ได้ เมื่อคิดแบบนี้ ความต่างเรื่องวิธีการเขียนตรงนี้ก็ไม่ต้องกังวล เพราะการทำแคชมันช่วยได้

--- จากนี้นอกประเด็นนิด ---

ถ้าลองเคยเขียนระบบใหญ่จริงๆ จะพบครับว่าอย่าไปกังวลปัญหาจุกจิกพวกนี้ ถ้ามีเวลาพอและระบบเสถียรจริง เราค่อยมาปรับโค้ดที่หลังก็ได้ แต่ก็ดูความจำเป็น กับความเป็นไปได้ด้วย

ในบางกรณี แม้ผมจะเขียน php คล่อง แต่บางกรณีภาษาอื่นทำงานได้ไวกว่า แล้ว php มันถึงเพดานของมัน ผมจะเลือกไปใช้ภาษาอื่นหรือระบบอื่นที่ไวกว่านี้ดีกว่า ซึ่งมันไม่ยากเลยในการศึกษา ขอแค่หาเว็บที่สอน best practice เจอ การจะย้ายงานไปบนระบบที่เบากว่าก็ไม่ใช่เรื่องยาก อย่างเช่นการทำ notification ก็เลี่ยงไปใช้ nodejs แทน ก็เบาโข และเราไม่ได้ย้ายงานทั้งหมดไป แต่ใช้ส่วนเดียว ที่เหลือก็ api ยิงกันไปมาภายใน


มันไม่ง่ายเลยที่จะทำ GIF ให้มีขนาดน้อยกว่า 20kB

By: itpcc
ContributoriPhoneRed HatUbuntu
on 22 November 2012 - 16:54 #509907 Reply to:509887
itpcc's picture

//กระอักเลือดไปสองสามหยด

อ่า ครับ ถือเป็นความรู้ใหม่เลย

ผมเองที่ผ่านมาเขียนสดตลอดเลย...(ถึงจะเป็นแค่เด็ก ม.5 ทำโปรเจกเล็กๆมาไม่เยอะก็เหอะ)

ตอนนี้ก็ศึกษา PHP Framework อยู่ ถือเป็นคำแนะนำที่ดี ขอบคุณมากครับ ^^


บล็อกส่วนตัวที่อัพเดตตามอารมณ์และความขยัน :P

By: EThaiZone
ContributorAndroidUbuntuWindows
on 22 November 2012 - 17:05 #509911 Reply to:509907
EThaiZone's picture

โอกาสยังมีอีกยาว ผมก็เริ่มเขียน PHP ตอนปวช.เหมือนกัน แต่กว่าผมจะจับ Framework ก็ช่วงเรียนป.ตรี ส่วนหนึ่งเพราะรู้ว่าถ้า OOP ไม่แม่น มันจะล่มเอา


มันไม่ง่ายเลยที่จะทำ GIF ให้มีขนาดน้อยกว่า 20kB

By: EThaiZone
ContributorAndroidUbuntuWindows
on 22 November 2012 - 16:25 #509894
EThaiZone's picture

แบบสั้นๆ (ฟังค์ชั่นเหล่านี้มันมากับ PHP มีก็ใช้มันเลย)

<?php
    $file="filelists.txt";
    $file_data=file_get_contents($file);
    preg_match_all('#best_H([0-9]+)_M([0-9]+)_S([0-9]+)#', $file_data, $matches);
    unset($file_data);  //ล้างที่คืน จะได้ไม่เป็นภาระของลูกหลาน...
    echo 'H = '.implode(',', $matches[1]).'\n';
    echo 'M = '.implode(',', $matches[2]).'\n';
    echo 'S = '.implode(',', $matches[3]).'\n';
?>

แบบโครตสั้น (เขียนแล้วเข้าใจทีเดียว อีก 1 เดือนมาดูอีกมีงง)

<?php
    preg_match_all('#best_H([0-9]+)_M([0-9]+)_S([0-9]+)#', file_get_contents('filelists.txt'), $matches);
    echo 'H = '.implode(',', $matches[1]).'\nM = '.implode(',', $matches[2]).'\nS = '.implode(',', $matches[3]).'\n';
?>

มันไม่ง่ายเลยที่จะทำ GIF ให้มีขนาดน้อยกว่า 20kB

By: kowito
Android
on 22 November 2012 - 16:46 #509905

ตัดเอาแบบสั้นๆนะครับ

import collections
def split_by_underscore(text):
    return str.split(text[5:13],'_')

#สมมุติว่าอ่านไฟล์มาเป็น list แล้ว
a = ['best_H1_M1_S1.out', 'best_H1_M1_S2.out', 'best_H1_M1_S2.out']
print collections.Counter(sum(map(split_by_underscore,a),[]))

กรรม อ่านโจทย์ผิด เดี๋ยวดึกๆมาแก้เพิ่ม

By: neizod
ContributorTraineeIn Love
on 22 November 2012 - 18:42 #509987
neizod's picture

ถ้าเป็น file processing แนะนำทำผ่าน shell script มากกว่า

ls -1 |
sed 's/best//;s/\.out//;s/_./ /g' |
awk 'BEGIN{ c[1]="H="; c[2]="M="; c[3]="S=" }
{ for (i in c) c[i] = c[i] $i "," }
END{ for (i in c) print c[i] }'