Home | First | Prev | Next | Last |
姓,名,メール,電話 Yamada,Takao,takao@yamada.com,123-456-7890のような行のある input.csv ファイルから「姓」と「電話」を取り出すのに
$ cut -d , -f 1,4 input.csv > output.csvとすればよいのですが、
Yamada,"Takao, Jr.",takao@yamada.com,123-456-7890となっている場合、上記のコマンドでは異なった結果が出ます。引用符で囲まれたコンマは飛ばさなければいけないのですが、cut コマンドではそれができません。
import csv inpfile = 'input.csv' outfile = 'output.csv' with open(outfile, 'w') as out: with open(inpfile) as inp: lines = csv.reader(inp) for line in lines: out.write(line[0] + ',' + line[3] + '\n')とすると、思い通りの結果を得ることができました。
shouta@shoufukutei.com,Yuji,Tanoshita kikuou@hayashiya.com,Hiroshi,Toyota takao@yamada.com,Takao,Yamada次のようにデータを得ました。
import csv with open('input.csv') as inp: rows = csv.reader(inp)
[[['shouta@shoufukutei.com'],['Yuji'],['Tanoshita']], [['kikuou@hayashiya.com'],['Hiroshi'],['Toyota']], [['takao@yamada.com'],['Takao'],['Yamada']]]というふうに、配列の中に配列が入っていますので、
for row in rows: sort_index = row[sort_key]で、ソートの基準になるコラムを指定し、それをソートインデックスとしました。そして、配列を文字列に変換する関数 join() を使って、data は data = [] として初期化しておいた上で、ソートインデックスとデータの文字列をそこに格納しました。
row_string = ','.join(row) data.append([sort_index, row_string])
for items in sorted(data): item = items[1]sort_key = 1 とすると、Hiroshi, Takao, Yuji の順にソートされるので、データラインは次のように並びかわります。
kikuou@hayashiya.com,Hiroshi,Toyota takao@yamada.com,Takao,Yamada shouta@shoufukutei.com,Yuji,Tanoshita
import csv data = [] with open('input.csv') as inp: rows = csv.reader(inp) for row in rows: data.append(row)そして lambda 式をつかって、ソート・キーを指定しました。lambda 式は、引数と返り値をコロン(:)で区切って記述するもので、def の代わりに使えます。
data2 = sorted(data, key=lambda items: items[2])たった一行で、ラストネーム順にソートできました。Python らしい記述になりました。
$ pip install notebookとするだけです。起動はターミナルから
$ jupyter notebookと記入して、行いました。
$ ssh penguin@192.168.XXX.XXX (XXX には実際のアドレスの数字が入る)と入力して、NAS のパスワードを入れて、PC から NAS を操作しました。NAS のディレクトリーをたどっていくと /opt/python3/bin/python3.10 があるのを見つけました。PC での Python へのパスは /usr/bin/python なので、これにあわせるため、
$ sudo ln -s /opt/python3/bin/python3.10 /usr/bin/pythonとして、リンクを作成しました。これで、PC 側で作成した Python スクリプトは、パスを書き換えることなく、そのまま転送して使えるようになりました。
sudo vim /usr/local/apache/conf/apache.conf次の部分に ExecCGI を追加しました。
<Directory "/share/Web/"> Options FollowSymLinks MultiViews ExecCGI AllowOverride All #Order allow,deny Require all granted </Directory>AddHandler はすでに "cgi-script .cgi" と設定されていましたので、そのままにしました。次のコマンドで apache.conf の設定ミスがないかどうか試しました。
$ /usr/local/apache/bin/apachectl configtest"OK" が出たので、次のコマンドで apache を再起動して設定を有効にしました。
$ sudo /usr/local/apache/bin/apachectl restart
AuthUserFile /share/CACHEDEV1_DATA/Web/admin/.htpasswd AuthType Basic AuthName "Password Protected Area" require valid-user/share/CACHEDEV1_DATA/Web/ が、NAS の Web データ・ディレクトリーで、admin/ はアクセス制限をかけるディレクトリーです。
/mnt/opt/apache/bin/にありました。それで、次のコマンドでパスワードファイルを作りました。
$ /mnt/opt/apache/bin/htpasswd -b -c /share/CACHEDEV1_DATA/Web/admin/.htpasswd {user} {password}上記の {user} や {password} には、もちろん実際のユーザとパスワードが入ります。また admin/ の部分を変更すれば、どこにでも .htaccess ファイルを置くことができます。
print(f"Set-Cookie: key={key_value};")これは Perl でも同じです。
use CGI; my $q = new CGI; $key_value = $q->cookie('key');Python では、http モジュールの cookies を使って、次のように取り出すことができるとの説明を見つけました。
from http import cookies cookie = cookies.SimpleCookie() key_value = cookie["key"].valueしかし、実際には、os モジュールで、あらかじめ cookie 情報をとりこんでおく必要がありました。
import os from http import cookies cookie = cookies.SimpleCookie() cookie.load(os.environ["HTTP_COOKIE"]) key_value = cookie["key"].value
import os from http import cookies try: cookie = cookies.SimpleCookie() cookie.load(os.environ["HTTP_COOKIE"]) key_value = cookie["key"].value except: key_value = ""
from datetime import date, timedelta today = datetime.today() weekday = today.weekday()曜日は 0 - 6 で返されます。0 が月曜日で、6 が日曜日ですから、きょうから次の日曜日までの日数は 6 - weekday となります。これを timedelta(days=days_to_Sunday) に入れて、次の日曜日の年月日を得ることができました。
nextSunday = today + timedelta(days=6 - weekday) print(date.strftime(nextSunday, '%Y-%m-%d'))
t := time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.UTC) week_day := int(t.Weekday())として得ることができました。time.Date() に渡す引数は
年 year 月 time.Month(month) 日 1 時 0 分 0 秒 0 ミリ秒 0 タイムゾーン time.UTCとなっています。
t = time.Date(year, time.Month(month + 1), 0, 0, 0, 0, 0, time.UTC) last_day := t.Day()
last_days := []int { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }2月の場合だけ、次の function で日数を得るようにしました。
func find_last_day (year int) (int) { if year % 4 == 0 && year % 100 != 0 || year % 400 == 0 { return 29 }else{ return 28 } }
var ( Bold = "\033[1m" Red = "\033[1m\033[31m" Green = "\033[1m\033[32m" Yellow = "\033[1m\033[33m" Blue = "\033[1m\033[34m" Purple = "\033[1m\033[35m" Cyan = "\033[1m\033[36m" Reset = "\033[0m" ) func color_print(day int) { if day < 10 { fmt.Printf(" %s% d%s ", Red, day, Reset) } else { fmt.Printf(" %s%d%s ", Red, day, Reset) } }色文字は、今は、Red しか使いませんが、後々のため、他の色もグローバル変数で定義しておきました。bold のほうが読みやすいので、すべて bold にしました。Gray は bold にするだけで White になるので、White は定義していません。
package color import ( "fmt" ) var ( Bold = "\033[1m" Red = "\033[1m\033[31m" Green = "\033[1m\033[32m" Yellow = "\033[1m\033[33m" Blue = "\033[1m\033[34m" Purple = "\033[1m\033[35m" Cyan = "\033[1m\033[36m" Reset = "\033[0m" ) func Color_print(day int) { if day < 10 { fmt.Printf(" %s% d%s ", Red, day, Reset) } else { fmt.Printf(" %s%d%s ", Red, day, Reset) } }main package からは
color.Color_print(day)として呼び出すようにしました。
module calendar go 1.20全体の配置は次のようになります。
[Go Source Root] ┗━━ calendar/ ┣━━ calendar.go ┣━━ mod.go ┗━━ color/ ┗━━ color.go
func split_pdf(pdf_file string) { app := "pdftk" args := []string{ pdf_file, "burst", "output", "PDF/" } cmd := exec.Command(app, args...) err := cmd.Run() if err != nil { log.Fatal(err) } }思ったより簡単に書くことができました。
package main import ( "log" "os" "os/exec" ) type saveOutput struct { savedOutput []byte } func (so *saveOutput) Write(p []byte) (n int, err error) { so.savedOutput = append(so.savedOutput, p...) return os.Stdout.Write(p) } func main() { wavfile := "sample.wav" mp3file := "sample.mp3" app := "lame" args := []string{ wavfile, mp3file } var so saveOutput cmd := exec.Command(app, args...) cmd.Stdin = os.Stdin cmd.Stdout = &so cmd.Stderr = os.Stderr err := cmd.Run() if err != nil { log.Fatal(err) } }
wget https://www.python.org/ftp/python/2.7.9/Python-2.7.9.tgz tar xzf Python-2.7.9.tgz cd Python-2.7.9 ./configure --enable-optimizations sudo make altinstallそして、Python3 と切り替えて使うことができるようにするため、alternative を設定しました。
sudo ln -sfn '/usr/local/bin/python2.7' '/usr/bin/python2' sudo update-alternatives --install /usr/bin/python python /usr/bin/python2 1けれども、Pdfbooklet は動きませんでした。Psfbooklet は Python3 で動いているようです。
$ pdftk source.pdf cat end-1 output reversed.pdf$ python pdfbook2 reversed.pdf これがうまくいきましたので、pdfbook2 にコードを書き加えて、右綴じの小冊子を作れるようにしました。GUI でなくても大丈夫で、これを pdfbook3 と名付けて使っています。
$ pdfjam sample.pdf --booklet 'true' --paper 'letter' --landscape --outfile sample-book.pdf
$ pdfjam sample.pdf --booklet 'true' --paper 'letter' --landscape --suffix 'book'
$ pdfjam sample.pdf --preamble '\usepackage{everyshi}\makeatletter\EveryShipout{\ifodd\c@page\pdfpageattr{/Rotate 180}\fi}\makeatother' --booklet 'true' --paper 'letter' --landscape --suffix 'book'
$ pdfjam sample.pdf 'last-1' --preamble '\usepackage{everyshi}\makeatletter\EveryShipout{\ifodd\c@page\pdfpageattr{/Rotate 180}\fi}\makeatother' --booklet 'true' --paper 'letter' --landscape --suffix 'book'とすると、期待通りのファイルを得ることができました。他にも、オプションを変更すれば、2-up シートを作ることができました。シェルスクリプトで pdfjam にオプションを渡すプログラムを書いて使っています。
#!/bin/bash if [[ $# != 1 ]]; then echo "Input directory." exit 1 fi mdir=$1 pattern="$mdir/*.mp3" fnames=`ls $pattern` for fname in $fnames; do echo "$fname" doneif 文では引数の数 $# をチェックしています。`ls $pattern` は ls を実行させるコマンドで、バッククォートで囲むのは perl と同じでした。for 文で ls が出力した配列 $fname からひとつづつのファイルを取り出し、echo で表示しています。
out=`mp3info -p %S ${fname}` min=$(($out / 60)) sec=$(($out % 60)) mp3name=`basename ${fname}` printf "%s %d:%02d\n" $mp3name $min $secmp3info の出力は秒ですので、分と秒で表示するため、printf を使いました。秒が一桁の場合、0 を付けるようにしました。
function mkspace() { size=0 for ((i=0; i < ${#mp3name}; i++)); do moji=${mp3name:$i:1} byte=$(printf "%s" "$moji" | wc -c) if [[ $byte == 3 ]]; then size=$((${size} + 2)) else size=$((${size} + 1)) fi done max=$((40 - ${size})) spc="" for ((i=0; i < $max; i++)); do spc="${spc}." done }まず、${#mp3name} でファイル名の長さを得て、${mp3name:$i:1} で、それを先頭から一文字づつ切り取りました。そして、その文字が何バイトあるかを printf "%s" "$moji" | wc -c でチェックしました。UTF-8 では日本語は 3バイトですので、size に 2 を加え、英数文字なら 1バイトですので、size に 1 を加えました。これで、画面上の文字列サイズを検出できました。再生時間表示の開始位置を 40 に固定し、そこから文字列サイズを引いて、スペースを作りました。
mkspace $mp3name printf "%s %s %d:%02d\n" $mp3name $spc $min $sec次のように表示されます。
01_My_Old_Kentucky_Home.mp3 .............. 2:46 02_Jeanie_With_the_Light_Brown_Hair.mp3 .. 3:04 03_Old_Black_Joe.mp3 ..................... 3:05 04_Shenandoa.mp3 ......................... 3:16 05_Home_On_the_Range.mp3 ................. 3:33 10_Swanee_River_故郷の人々.mp3 ........... 3:21 11_Beautiful_Dreamer_夢路より.mp3 ........ 3:18 12_Oh_Susanna_おおスザンナ.mp3 ........... 1:46これは、いろんなところで応用できそうです。
#!/usr/bin/pwsh # playtime.ps1 # 2023.06.05ハッシュ・バング、スクリプト名、作成日の順です。
if ($Args.Count -eq 1) { Write-Host "$($PSStyle.bold)== Playtime (pwsh version) ==$($PSStyle.BoldOff)" -ForegroundColor "Green" } else { Write-Host "Input directory name." exit(1) }$Args.Count は引数の個数です。一つだけの場合、タイトルを表示するようにしました。'==' は使えないので、 '-eq' で個数を判定しています。'$($PSStyle.bold)' と '$($PSStyle.BoldOff)' は ANSI 制御コードで、太文字の指定と解除をしています。文字の色は '-ForegroundColor "Green"' で指定しています。'Write-Host' は println() と同じような働きをします。
$dir = $Args[0] $mp3files = Get-ChildItem ${dir}/*.mp3 foreach ($mp3file in $mp3files) { ($min, $sec) = findPlayTime($mp3file)
Function findPlayTime($mp3file) { $sec = & mp3info -p %S $mp3file $min = [int]($sec / 60) $sec = $sec % 60 return $min, $sec }外部プログラム 'mp3info' は & を使って呼び出し、その結果を $sec に代入しました。$sec は秒数ですので、'$out / 60' で「分」に、'$out % 60' で「秒」を得ています。ただし、そのままだと「分」が小数点以下まで表示されてしまうので、'[int]' で整数に換算しています。
foreach ($mp3file in $mp3files) { ($min, $sec) = findPlayTime($mp3file) $mp3name = Split-Path $mp3file -Leaf $spc = MakeSpace $mp3nameFunction MakeSpace() は、ファイル名($mp3name)を受け取り、一文字づつのバイト数を 'wc -c' でチェックしています。Bash と違って、3バイト文字の返り値が '4'、1バイト文字は '2' となったので、'$byte -= 1' で調整しています。どうしてそうなるのか、まだ調べていません。
Function MakeSpace($mp3name) { $len = ${mp3name}.Length $size = 0 for ($i = 0; $i -lt $len; $i++) { $moji = ${mp3name}.Substring($i, 1) $byte = $moji | wc -c $byte -= 1 if ($byte -eq 3) { $size = $size + 2 } else { $size = $size + 1 } } $max = 50 - $size $spc = " " for ($i = 0; $i -lt $max; $i++) { $spc = " $spc" } return $spc }この関数は、それを呼び出しているメインルーチンの前に置かないとエラーになります。
Write-Host "$($PSStyle.bold)== Playtime (pwsh version) ==$($PSStyle.BoldOff)" -ForegroundColor "Green" if ($Args.Count -ne 1) { Write-Host "Input directory name." exit(1) } $dir = $Args[0] $mp3files = Get-ChildItem ${dir}/*.mp3 $total = 0 foreach ($mp3file in $mp3files) { ($min, $sec) = findPlayTime($mp3file) $total = $total + $min * 60 + $sec $mp3name = Split-Path $mp3file -Leaf $spc = MakeSpace $mp3name "{0} {1} {2:00}:{3:00}" -f $mp3name, $spc, $min, $sec } $totalmin = [int]($total / 60) $totalsec = $total % 60 if ($totalmin -gt 60) { $totalhur = [int]($totalmin / 60) $totalmin = $totalmin % 60 "$($PSStyle.bold)Total {0:00}:{1:00}:{2:00}$($PSStyle.BoldOff)" -f $totalhur, $totalmin, $totalsec } else { "$($PSStyle.bold)Total {0:00}:{1:00}$($PSStyle.BoldOff)" -f $totalmin, $totalsec }タイトル表示部分では、$($PSStyle.bold) と $($PSStyle.BoldOff) で太文字表示とその解除を示しています。-ForegroundColor "Green" で、文字列の色を指定しています。また、"{0} {1} {2:00}:{3:00}" -f $mp3name, $spc, $min, $sec の部分では -f オペレーターを使って、他の言語の printf と同じような働きをさせています。
$date = "June 12, 2023" [regex]$p = '^([A-z]+) ([0-9]+), ([0-9]+)$' $m = $p.match($date) $monthname = $m.groups[1] $day = $m.groups[2] $year = $m.groups[3]正規表現のパターンのかっこでくくった部分が $m.groups の各要素に格納されるので、それを数字で引き出すわけです。$m.groups[1] が月名、$m.groups[2] が日、$m.groups[3] が年を格納します。
$date = "June 12, 2023" [regex]$p = '^(?<monthname>[A-z]+) (?<day>[0-9]+), (?<year>[0-9]+)$' $m = $p.match($date) $monthname = $m.groups['monthname'] $day = $m.groups['day'] $year = $m.groups['year']かっこの内側に '?' を置き、すぐ後に、名前を '<>' でくくればよいだけです。取り出すときには、数字でなく、名前を入れればよいので、数字で取り出すよりは、分かりやすいです。
$monthnames = ("", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "Novenber", "December") $LastDays = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
$monthname = $monthnames[$month] Write-Host "${monthname}, ${y}" Write-Host "SUN MON TUE WED THU FRI SAT"
$firstDayOfWeek = (Get-Date -Year $y -Month $m -Day 1).DayOfWeek.value__で獲得してから、曜日タイトルにそろえるため、1日までに空白で埋めるようにしました。
$space = " " * ($firstDayOfWeek -gt 0) for ($i=0; $i -lt $firstDayOfWeek; $i++){ $space = $space + " " }
$weekValue = $firstDayOfWeek $weekLine = $space for ($day = 1; $day -le $lastDay; $day++){ if ($weekValue -eq 7) { Write-Host $weekLine $weekLine = "" $weekValue = 0 } if ($weekValue -eq 0) { if ($day -gt 9) { Write-Host -NoNewline " " } else { Write-Host -NoNewline " " } } if ($day -ge 9) { $weekLine = $weekLine + $day + " " } else { $weekLine = $weekLine + $day + " " } $weekValue += 1 } write-Host $weekLine
$a = $Year % 19 $b = [int][Math]::Floor($Year / 100) $c = $Year % 100 $d = [int][Math]::Floor($b / 4) $e = $b % 4 $f = [int][Math]::Floor((8 * $b + 13) / 25) $g = (19 * $a + $b - $d - $f + 15) % 30 $h = [int][Math]::Floor($c / 4) $i = $c % 4 $j = (32 + 2 * $e + 2 * $h - $g - $i) % 7 $k = [int][Math]::Floor(($a + 11 * $g + 22 * $j) / 451) $Month = [int][Math]::Floor(($g + $j - 7 * $k + 114) / 31) $Day = ($g + $j - 7 * $k + 114) % 31 + 1
a := year % 19 b := year / 100 c := year % 100 d := b / 4 e := b % 4 f := (b + 8) / 25 g := (b - f + 1) / 3 h := (19 * a + b - d - g + 15) % 30 i := c / 4 j := c % 4 k := (32 + 2 * e + 2 * i - h - j) % 7 l := (a + 11 * h + 22 * k) / 451 month := (h + k - 7 * l + 114) / 31 day := ((h + k - 7 * l + 114) % 31) + 1
Home | First | Prev | Next | Last |