以前作成した&csv_load()でCSVファイルから読み込んだデータからキーワードが含まれる行を抽出します。
使い方
・前回と同様に配列変数「@csv_line」に対して操作するので、グローバル変数とするかローカル変数の宣言をして下さい。
・検索対象としない列は「@csv_search_hide」の同じ配列に数列「-1」をセットして下さい。これもグローバル変数・ローカル変数として下さい。
・&csv_search(検索ワード,単語数制限);
検索ワードは(半角・全角)スペース区切りで、全ての単語が含まれる行を抽出します。
単語数制限は3とすれば「単語1 単語2 単語3 単語4」と検索した時、4単語あるの以上は無視します。
・キーワードが空値の時は@csv_lineが空になります。
検索ワードについて
・一般的な検索サイトと同様に単語のスペース区切りで検索できます。
・制御文字(下記)により AND OR NOT などの検索ができます。
・キーワード英字は小文字大文字関係無しです。
制御文字
・* + – ” ‘ スペース(全半角) が使えます。
・「A B C」とするとAとBとCの全てが含まれた行のみ出力します(AND)
・「A*B*C」も同上です
・「A+B+C」とするとAとBとCの1つでも含まれた行のみ出力します(OR)
・「-A-B-C」とするとAとBとCの全てが含まれない行のみ出力します(NotAND)
(実際の動作はA はNotOR して B と C だけNotANDです)
・「-A*-B*-C」も同上です
・「-A+-B+-C」とするとAとBとCのどれかが含まれない行のみ出力します(NotOR)
※マイナスをつける位置は単語の前だけです。記号の前につけても無視されます。
※記号の前後のスペースは無視されます。(「A + B * – D E」と「A+B*-D E」は同じ)
・シングル・ダブルクオーテーション で括ると、括られた中で * + – スペースを検索対象にできます。
「”A A” + “***” – “—“」
・またダブルクオーテーション内ではシングルクォーテーションが、シングルクォーテーション内ではダブルクオーテーションが検索対象にできます。
「””'”」
※ダブルクオーテーションやシングルクォーテーションが1つか無い場合は検索文字として処理されます。
注意点
・キーワードが空値の時は@csv_lineが空になります。
備忘録
プログラムが長すぎて何をやってるか忘れそうなので覚書
・前半のの検索キーワードの整頓では、1文字ずつ文字を拾い ” ‘ * + – の記号によって処理を分岐
・後半は該当する行にフラグを立て、and or 比較して出力しています。
プログラム
#------------------------------------------------- # CSV形式の配列変数(@csv_line)からキーワードが含まれる行を抽出する。 #------------------------------------------------- sub csv_search{ #0=keyword 1=limit 2=mode my($k)=$_[0]." ";#※処理上の半角スペースを足している。 my($i,$j); #キーワード抽出用変数 my($start)=0; my($mode)="0"; #1=and 2=or 3=not-and 4=not-or my($count)=0; my($utf8_space,@keys,$utf); #データ抽出用変数 my(@csv,@line,@index,$v); #- - - - - - - - - - - - - - - - - - - - - # 検索キーワードの整頓 #- - - - - - - - - - - - - - - - - - - - - $k =~ s/\x0D//g; #検索キーワードで使えない文字を除外する $k =~ s/\x0A//g; $k = &csv_format_save($k); #←検索ワードをセーブ形式に・・配列側で逐次表示形式に変換すると時間がかかるため utf8::decode($k); #utf8時にカウントがおかしくなる対策 $utf8_space=" "; #そのままだとdecodeした値と比較演算できないので utf8::decode($utf8_space); for ($i = 0; $i <= length($k)-1; $i++){ if (substr($k,$i,1) eq '"'){ #ダブルクオーテーションで括られている時の処理 for ($j = $i+1; $j <= length($k)-1; $j++){ if (substr($k,$j,1) eq '"'){ if ($start != $i){ $mode="1"; } if (substr($k,$i+1,$j-($i+1)) ne ""){ $utf=substr($k,$i+1,$j-($i+1)); utf8::encode($utf); $keys[$#keys+1]="$mode,$utf"; $count++; } $i=$j; $start=$j+1; $mode="1"; last; } } }elsif (substr($k,$i,1) eq "'"){ #シングルクオーテーションで括られている時の処理 for ($j = $i+1; $j <= length($k)-1; $j++){ if (substr($k,$j,1) eq "'"){ if ($start != $i){ $mode="1"; } if (substr($k,$i+1,$j-($i+1)) ne ""){ $utf=substr($k,$i+1,$j-($i+1)); utf8::encode($utf); $keys[$#keys+1]="$mode,$utf"; $count++; } $i=$j; $start=$j+1; $mode="1"; last; } } }else{ #括られていない時の処理 if (substr($k,$i,1) eq " "){ if ($start != $i){ $utf=substr($k,$start,$i-($start)); utf8::encode($utf); $keys[$#keys+1]="$mode,$utf"; $count++; $mode="1"; } $start=$i+1; }elsif (substr($k,$i,1) eq $utf8_space ){ #全角スペース if ($start != $i){ $utf=substr($k,$start,$i-($start)); utf8::encode($utf); $keys[$#keys+1]="$mode,$utf"; $count++; $mode="1"; } $start=$i+1; }elsif (substr($k,$i,1) eq "*"){ if ($start != $i){ $utf=substr($k,$start,$i-($start)); utf8::encode($utf); $keys[$#keys+1]="$mode,$utf"; $count++; } $mode="1"; $start=$i+1; }elsif (substr($k,$i,1) eq "+"){ if ($start != $i){ $utf=substr($k,$start,$i-($start)); utf8::encode($utf); $keys[$#keys+1]="$mode,$utf"; $count++; } $mode="2"; $start=$i+1; }elsif (substr($k,$i,1) eq "-"){ if ($start != $i){ $utf=substr($k,$start,$i-($start)); utf8::encode($utf); $keys[$#keys+1]="$mode,$utf"; $count++; } if ($mode eq "0"){ if ($#keys==-1){ $mode="4"; }else{ $mode="3"; } }elsif ($mode eq "2"){ $mode="4"; }else{ $mode="3"; #3と4の時 はNot-AND } $start=$i+1; } } #リミッター($_[0]が0以上の正数なら$_[0]に従い、それ以外の時は5ワードで終了) if ($_[1] > 0 ){ if ($_[1] <= $count ){last;} }else{ if (5 <= $count ){last;} } } #- - - - - - - - - - - - - - - - - - - - - #検索非対象を除外した検索用の配列(@line)を作成 #- - - - - - - - - - - - - - - - - - - - - for ($i = 0; $i <= $#csv_line; $i++){ @csv=split(/,/,$csv_line[$i]); #←検索ワード側を変換済みのためcsv_splitを使用してない for ($j = 0; $j <= $#csv; $j++){ if ($csv_search_hide[$j] != -1){ $line[$i].="$csv[$j],"; } } } #- - - - - - - - - - - - - - - - - - - - - # 抽出と出力 #- - - - - - - - - - - - - - - - - - - - - for ($j = 0; $j <= $#keys; $j++){ $v = $keys[$j]; $v =~ s/\\/\\\\/g; #正規表現でエラーの出る文字を置換する。 $v =~ s/\+/\\+/g; $v =~ s/\*/\\*/g; $v =~ s/\?/\\?/g; $v =~ s/\./\\./g; $v =~ s/\(/\\(/g; $v =~ s/\)/\\)/g; $v =~ s/\[/\\[/g; $v =~ s/\]/\\]/g; $v =~ s/\{/\\{/g; $v =~ s/\}/\\}/g; $v =~ s/\|/\\|/g; $v =~ s/\^/\\^/g; $v =~ s/^[0-9]+,//; if ($keys[$j] =~ /^1,/){ #and for ($i = 0; $i <= $#csv_line; $i++){ if ($index[$i] == 1){ if ($line[$i] !~ /$v/i){$index[$i]=-1}; } } }elsif($keys[$j] =~ /^3,/){ #not-and for ($i = 0; $i <= $#csv_line; $i++){ if ($index[$i] == 1){ if ($line[$i] =~ /$v/i){$index[$i]=-1}; } } }elsif($keys[$j] =~ /^2,/){ #or for ($i = 0; $i <= $#csv_line; $i++){ if ($line[$i] =~ /$v/i){ $index[$i]=1 }; } }elsif($keys[$j] =~ /^4,/){ #not-or for ($i = 0; $i <= $#csv_line; $i++){ if ($line[$i] !~ /$v/i){ $index[$i]=1 }; } }else{ for ($i = 0; $i <= $#csv_line; $i++){ if ($line[$i] =~ /$v/i){ $index[$i]=1 }; } } } #@csv_lineに出力 @line=(); for ($i = 0; $i <= $#csv_line; $i++){ if ($index[$i] == 1){ $line[$#line+1]=$csv_line[$i]; } } @csv_line=@line; }