Mendapatkan regex untuk mencocokkan nama file

2

Saya memiliki skrip yang mencantumkan sekelompok file yang cocok dengan kriteria tertentu. Ini menghasilkan nama file saja dan ada banyak teks yang tidak perlu.

Contoh string adalah:

[gg]_Magi_-_13_[DB38165F].mkv

Apa yang ingin saya capai dalam output adalah:

[gg]_Magi_-_13

Saya sudah bisa mengganti garis bawah tapi saya tidak berhasil memotong [CRC32] .mkv berhasil. Saya juga membatasi jumlah karakter dan menempatkan ellipsis di bagian akhir jika mereka melampaui 28 karakter tetapi bahkan jika tidak melampaui 28 karakter, itu masih menambahkan ellipsis di akhir.
Kode untuk itu adalah:

print substr( $0, 0, 28 )"[…]"}

Bantuan untuk salah satu dari masalah ini akan sangat dihargai.

user181353
sumber
Bahasa apa yang Anda gunakan? Juga, apakah semua nama file dalam format itu?
Aluísio A. S. G.
@ Aluísio A. S. G. - Saya melewati semua itu melalui skrip bash. Sebagian besar jika tidak semua nama file mengikuti format itu.
user181353
@DW Apakah Anda pernah menggunakan manajer file bernama Ranger? Ini memungkinkan Anda untuk mengubah nama file secara massal menggunakan Vim (yang, seperti yang Anda ketahui, memungkinkan Anda untuk melakukan pengeditan blokir secara vertikal). Saya menemukan bahwa itu benar-benar membuat penggantian nama yang kompleks sangat mudah (biasanya hanya memerlukan beberapa pengeditan sederhana). github.com/hut/ranger
hayavuk
@OP Saya baru saja melihat ada masalah dengan masalah Anda. Jika Anda memotong semua nama file menjadi 28 karakter dengan elipsis, dan Anda memiliki banyak file yang panjangnya 32 karakter, di mana penghitungnya melebihi 28 karakter, Anda akan mengganti nama file menjadi nama file yang sama dan berakhir dengan satu file. Misalnya., [blahblah] blahblahblahblahblah 01 dan [blahblah] blahblahblahblahblah 02 keduanya menjadi [blahblah] blahblahblahblahb... (tidak ada file yang berbeda)
hayavuk

Jawaban:

2

Saya pikir solusi terpendek untuk memenuhi semua kriteria adalah yang ini

awk '{
    if (match($0, "^(.*)_[^_]+$", a)) {
        print substr(a[1], 1, 27) (length(a[1]) > 27 ? "..." : "")
    }
}'
sparkie
sumber
Dua garis murni bash akan melakukannya juga, yang bisa dibilang lebih pendek, belum lagi lebih cepat. Lihat Jawabanku .
kopischke
1
sed -e 's/_\[.*\.mkv//' -e 's/^\(.\{28\}\).*/\1.../' file.txt

Bit pertama menghapus _[blah].mkv, dan bit kedua mencetak 28 karakter pertama, dan menempatkan ... pada akhirnya - tetapi jika string kurang dari 28 karakter, itu hanya mencetak nama file yang dilucuti, tanpa menambahkan elips.

Jika ekstensi file tidak selalu menjadi * .mkv, Anda dapat menggunakan ini (sebagai tambahan, $ berarti 'sampai akhir baris'):

sed -e 's/_\[.*$//' -e 's/^\(.\{28\}\).*/\1.../' file.txt
evilsoup
sumber
Bagus, tetapi saya selalu menemukan sed sedikit berlebihan untuk manipulasi string yang cukup mendasar. Lihat Jawabanku untuk dua baris murni bash yang mencapai hasil yang sama.
kopischke
1

Meskipun awk, sed dan perusahaan memiliki kelebihan mereka, mereka tidak diperlukan untuk ini. Anda dapat dengan mudah mencapai semua yang Anda minta hanya dengan menggunakan bash operasi string dan pencocokan pola. Dengan asumsi Anda telah menetapkan nama file Anda $name:

name="${name%_\[*\].*}"

akan memotong jenis file dan mengurutkan dari CRC $name. Jika Anda perlu memastikan 100% bahwa Anda hanya memotong CRC, Anda dapat menggunakan regex yang diperluas daripada yang di atas:

[[ $name =~ (.*)_\[[[:xdigit:]]{8}\]\..*$ ]] && name="${BASH_REMATCH[1]}"

Pemotongan nama yang lebih dari 28 karakter kemudian dicapai dengan:

(( ${#name} > 28 )) && name="${name::27}…"

- dua baris bash total (tidak termasuk logika, loop atau lainnya, untuk mendapatkan nama file Anda ke var, dan kode output, tentu saja), tanpa eksternal. Keuntungan utama adalah bahwa kodenya sangat cepat, karena shell tidak pernah harus meluncurkan binari eksternal.

kopischke
sumber
Oke, itu sangat rapi. Pastinya jawaban terbaik di sini.
evilsoup
0

Coba fungsi bash ini (peringatan: tidak diuji):

function convert_filename {
    # Regex guide:
    #   ^(.*)_?                everything since the beginning of the string,
    #                          optionally followed by an underscore
    #   \[[a-fA-F0-9]{8}\]    8 hexadecimal characters, surrounded by []
    #   \.(.\w+)$              filename extension at the end of the string
    local r="$(echo "$1" | sed -r 's/^(.*)_?\[[a-fA-F0-9]{8}\]\.(.\w+)$/\1/')"
    if (( ${#r} < 28 )); then
        # Outputs $r
        echo "$r"
    else
        # Outputs the first 27 characters from $r followed by an ellipsis
        echo "${r::27}…"
    fi
}
Aluísio A. S. G.
sumber
0

Bukan solusi terbersih tetapi Anda bisa melakukan ini:

 echo "[gg]_Magi_-_13_[DB38165F].mkv" | awk -F '_' '{print $1"_"$2"_"$3"_"$4}'

EDIT: Meh, goreskan jawaban ini. Itu tidak akan memberimu elipsis.

hayavuk
sumber