以前作成した&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;
}