dak ブログ

python、rubyなどのプログラミング、MySQL、サーバーの設定などの備忘録。レゴの写真も。

jQuery での DOM 操作

2022-03-27 13:08:03 | javascript
jQuery での DOM 操作のメモ。

以下の DOM に対して追加・削除等の操作を行います。
  <div id="d1">
    <div id="d2-1">
      <div id="d3-1">
        <p id="p4-1">p4-1 text</p>
        <p id="p4-2">p4-2 text</p>
      </div>
      <div id="d3-2"></div>
    </div>
    <div id="d2-2">
      <div id="d3-3"></div>
      <div id="d3-4"></div>
      </div>
    </div>
  </div>

■末尾に追加
  $(`<div id="d2-3"></div>`).appendTo($('#d1'));
  console.log($('#d1').html());
-->
    <div id="d2-1">
      <div id="d3-1">
        <p id="p4-1">p4-1 text</p>
        <p id="p4-2">p4-2 text</p>
      </div>
      <div id="d3-2"></div>
    </div>
    <div id="d2-2">
      <div id="d3-3"></div>
      <div id="d3-4"></div>
      </div>
    <div id="d2-3"></div>

■指定要素の前に子を追加
  $(`<div id="d2-0"></div>`).insertBefore($('#d2-1'));
  console.log($('#d1').html());
-->
    <div id="d2-0"></div><div id="d2-1">
      <div id="d3-1">
        <p id="p4-1">p4-1 text</p>
        <p id="p4-2">p4-2 text</p>
      </div>
      <div id="d3-2"></div>
    </div>
    <div id="d2-2">
      <div id="d3-3"></div>
      <div id="d3-4"></div>
      </div>

■指定要素の次に子を追加
<pre>
$(`<div id="d3-5"></div>`).insertAfter($('#d3-4'));
console.log($('#d1').html());
-->
<div id="d2-1">
<div id="d3-1">
<p id="p4-1">p4-1 text</p>
<p id="p4-2">p4-2 text</p>
</div>
<div id="d3-2"></div>
</div>
<div id="d2-2">
<div id="d3-3"></div>
<div id="d3-4"></div><div id="d3-5"></div>
</div>

■指定要素を削除
  $('#d3-1').remove();
  console.log($('#d1').html());
-->
    <div id="d2-1">
      
      <div id="d3-2"></div>
    </div>
    <div id="d2-2">
      <div id="d3-3"></div>
      <div id="d3-4"></div>
      </div>

■指定要素の子を削除(空にする)
  $('#d3-1').empty();
  console.log($('#d1').html());
-->
    <div id="d2-1">
      <div id="d3-1"></div>
      <div id="d3-2"></div>
    </div>
    <div id="d2-2">
      <div id="d3-3"></div>
      <div id="d3-4"></div>
      </div>

■繰り返し
  $('#d3-1').children().each((i, node) => {
    console.log($(node).text());
  });
-->
p4-1 text
p4-2 text


jQuery でよく使うセレクタ

2022-03-27 12:38:42 | javascript
jQuery でよく使うセレクタの使い方のメモ。

以下の DOM に対してセレクタを試してみます。
  <div id="d1">
    <div id="d2-1">
      <div id="d3-1">
        <p id="p4-1">p4-1 text</p>
        <p id="p4-2">p4-2 text</p>
      </div>
      <div id="d3-2"></div>
    </div>
    <div id="d2-2">
      <div id="d3-3"></div>
      <div id="d3-4"></div>
      </div>
    </div>
  </div>

■id指定
  d = $('#d1');
  console.log(d.attr('id'));
  console.log(d.constructor.name);
-->
d1
S

■子要素のタグ指定
  ns = $('#d1 > div');
  console.log(ns.length);
  console.log(ns[0].constructor.name);
  console.log($(ns[0]).attr('id'));
  console.log($(ns[1]).attr('id'));
-->
2
HTMLDivElement
d2-1
d2-2

■子孫のタグ指定
  ps = $('#d1 p');
  console.log(ps.length);
  console.log(ps[0].constructor.name);
  console.log($(ps[0]).text());
  console.log($(ps[1]).text());
-->
2
HTMLParagraphElement
p4-1 text
p4-2 text

■子孫のタグ指定
  ps = $('#d1 p');
  console.log(ps.length);
  console.log($(ps[0]).text());
  console.log($(ps[1]).text());
-->
2
p4-1 text
p4-2 text

■子孫を検索
  d = $('#d1');
  ps = d.find('p');
  console.log(ps.length);
  console.log($(ps[0]).text());
  console.log($(ps[1]).text());
-->
2
selector1.html:82 p4-1 text
selector1.html:83 p4-2 text

■前の要素
  console.log('前の要素');
  d = $('#d2-2').prev();
  console.log($(d).attr('id'));
-->
d2-1

■次の要素
  d = $('#d2-1').next();
  console.log($(d).attr('id'));
-->
d2-2


jQuery でのイベント処理

2022-03-26 13:16:24 | javascript
jQuery でのイベント処理のメモ。

ボタンが押された場合のクリックイベントは、.click(() => {...}) で登録します。
以下の例では、「追加」ボタンを押下すると、その直下に行を追加します。
「削除」ボタンを押すとその行を削除します。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>test1</title>
</head>
<body>
<h3>jQuery でのイベント処理</h3>
<table border="1">
<tbody>
<tr>
<td><input type="text" name="memo"></td>
<td><input type="button" name="add" value="追加"></td>
</tr>
</tbody>
</table>
</body>
<script type="text/javascript" src="jquery-3.6.0.min.js"></script>
<script type="text/javascript">
function add_row(btn) {
  const new_row = $(`
  <tr>
  <td><input type="text" name="memo"></td>
  <td>
  <input type="button" name="add" value="追加">
  <input type="button" name="del" value="削除">
  </td>
  </tr>
  `);
  // ボタンが押された行の直後の行に追加
  const row = btn.parent().parent();
  new_row.insertAfter(row);

  // イベントハンドラ: 追加
  const add_btn = new_row.find('input[name="add"]');
  add_btn.click(() => { add_row(add_btn); });

  // イベントハンドラ: 削除
  const del_btn = new_row.find('input[name="del"]');
  del_btn.click(() => { del_row(del_btn); });
}

function del_row(btn) {
  // ボタンが押された行を削除
  const row = btn.parent().parent();
  row.remove();
}

(() => {
  const add_btn = $('input[name="add"]');
  add_btn.click(() => { add_row(add_btn); });
})();
</script>
</body>
</html>


BigQuery で json オブジェクト内の array の処理

2022-03-26 12:18:28 | GCP
BigQuery で json オブジェクト内の array を処理する方法のメモ。
まず、BigQuery のテーブルに以下のような json データを登録します。
insert into `test1.tbl1` (json) values ('''
{"type": "search", "uid": "004", "kw": "フライパン", "items": [
{"rank": 1, "id": "001", "title": "商品1"},
{"rank": 2, "id": "002", "title": "商品2"},
{"rank": 3, "id": "003", "title": "商品3"}
]}
''');

insert into `test1.tbl1` (json) values ('''
{"type": "search", "uid": "004", "kw": "鍋", "items": [
{"rank": 1, "id": "002", "title": "商品2"},
{"rank": 2, "id": "003", "title": "商品3"},
{"rank": 3, "id": "004", "title": "商品4"}
]}
''');

上記のデータから、kw と id を抽出するには以下のクエリを実行します。
select
  json_extract_scalar(t1.json, "$.kw") as kw
  , json_value(item, "$.id") as id
from
  `test1.tbl1` as t1
left join
  unnest(json_query_array(json_extract(t1.json, "$.items"))) as item
where
  json_extract_scalar(t1.json, "$.type") = "search"
;

実行結果は以下の通り、kw と id を抽出できています。
行  kw          id
1   フライパン  001
2   フライパン  002
3   フライパン  003
4   鍋          002
5   鍋          003
6   鍋          004


mysql で重複するレコードを登録しない方法

2022-03-25 00:10:41 | mysql
mysql で重複するレコードを登録しない方法のメモ。
以下のようにテーブルを作成し、エラーにならないように重複するレコードを登録する insert 文を実行します。
create table test1 (
       id    integer not null auto_increment,
       name  varchar(100) not null,

       primary key (id),
       unique key (name)
);

insert into test1 set name = 'name1';
insert into test1 set name = 'name2';
insert into test1 set name = 'name3';

■DB登録内容
mysql> select * from test1;
+----+-------+
| id | name  |
+----+-------+
|  1 | name1 |
|  2 | name2 |
|  3 | name3 |
+----+-------+

■レコード登録
insert ignore into ~ でレコードを登録します。
insert ignore into test1 set name = 'name1';
insert ignore into test1 set name = 'name2';
insert ignore into test1 set name = 'name4';

■DB登録内容確認
mysql> select * from test1;
+----+-------+
| id | name  |
+----+-------+
|  1 | name1 |
|  2 | name2 |
|  3 | name3 |
|  6 | name4 |
+----+-------+

id が name1、name2 分だけインクリメントされています。

次に、テーブルを作り直して、insert ~ where not exists ~ でレコードを登録します。
■レコード登録
insert into test1 (name)
select * from (select 'name1') as tmp
where not exists (select 1 from test1 where name = 'name1');

insert into test1 (name)
select * from (select 'name2') as tmp
where not exists (select 1 from test1 where name = 'name2');

insert into test1 (name)
select * from (select 'name5') as tmp
where not exists (select 1 from test1 where name = 'name5');

■DB登録内容確認
mysql> select * from test1;
+----+-------+
| id | name  |
+----+-------+
|  1 | name1 |
|  2 | name2 |
|  3 | name3 |
|  4 | name5 |
+----+-------+

重複レコードで id がインクリメントされずに、連番になっていることがわかります。


Typescript で chevrotain による構文解析

2022-03-23 00:24:55 | python
Typescript で chevrotain による構文解析を試してみました。
受理する構文は以下の2つです。
{数字} + {数字}
{数字} - {数字}

chevrotain で文字列を解析して、上記の計算結果を返します。
■文法
calc ⇒ expr
expr ⇒ val Plus val
val Minus val
val ⇒ [0-9]+
Plus ⇒ +
Minus ⇒ -

■プログラム
import { CstParser, Lexer, createToken, Rule } from 'chevrotain'

// lexer
const Num = createToken({ name: "Num", pattern: /[0-9]+/ });
const Plus = createToken({ name: "Plus", pattern: /[+]/ });
const Minus = createToken({ name: "Minus", pattern: /[-]/ });

const allTokens = [
  Num,
  Plus,
  Minus,
];

const calcLexer = new Lexer(allTokens);

// parser
class CalcParser extends CstParser {
  public value_stack: any[] = [];

  constructor() {
    super(allTokens);
    this.performSelfAnalysis();
  }

  public calc = this.RULE("calc", () => {
    this.SUBRULE(this.expr);
    if (! this.RECORDING_PHASE) {
      const obj = this.value_stack.pop();
      this.value_stack.push(obj);
    }
  });

  public expr = this.RULE("expr", () => {
    const item1: any = this.SUBRULE(this.val);
    let val1: any;
    if (! this.RECORDING_PHASE) {
      const obj1: any = this.value_stack.pop();
      val1 = obj1.value;
    }

    let val2: any;
    const item: any = this.OR([
      { ALT: () => {
        this.CONSUME1(Plus);
        this.SUBRULE1(this.val);
        if (! this.RECORDING_PHASE) {
          const obj2 = this.value_stack.pop();
          val2 = obj2.value;
          this.value_stack.push({ value: val1 + val2 });
        }
      }},
      { ALT: () => {
        this.CONSUME2(Minus);
        this.SUBRULE2(this.val);
        if (! this.RECORDING_PHASE) {
          const obj2 = this.value_stack.pop();
          let val2 = obj2.value;
          this.value_stack.push({ value: val1 - val2 });
        }
      }},
    ]);
  });

  private val = this.RULE("val", () => {
    const item: any = this.CONSUME(Num);
    if (! this.RECORDING_PHASE) {
      this.value_stack.push({ value: parseInt(item.image) });
    }
  });
}

const parser = new CalcParser();
const productions: Record<string, Rule> = parser.getGAstProductions();

const texts = [
  '1+2',
  '7-3',
];

for (let text of texts) {
  console.log(text);

  let lex_result = calcLexer.tokenize(text);
  parser.input = lex_result.tokens;
  parser.calc();
  const obj = parser.value_stack.pop();
  console.log(JSON.stringify(obj, null, 2));
}

■実行結果
1+2
{
  "value": 3
}
7-3
{
  "value": 4
}


python での遺伝的アルゴリズムによるパラメータの最適化

2022-03-19 12:35:37 | python
python で geneticalgorithm2 を用いて遺伝的アルゴリズム(GA: Genetic Algorithm)で
パラメータの最適化を試してみました。

インストール方法は以下の通りです。
numpy を利用していますので、numpy がインストールされていなければ、numpy もインストールします。
pip install numpy
pip install geneticalgorithm2


今回は、z = (x-2)(x-4)+(y-6)(y-8) を最小とする (x, y) を GA で求めてみました。
この関数の形状は以下の GeoGebra のサイトで確認することができます。
https://www.geogebra.org/3d?lang=ja
(3, 7) で最小値となります。

■プログラム
import numpy as np
from geneticalgorithm2 import geneticalgorithm2 as ga

# 最小化する関数
def f(p):
    x = p[0]
    y = p[1]
    z = (x - 2) * (x - 4) + (y - 6) * (y - 8)
    return z

# x, y のそれぞれの探索範囲
varbound = np.array([[0, 10], [0, 10]])

# パラメータ(指定しなければデフォルト)
params = {
    'max_num_iteration': 100,
    'population_size': 100,
}

model = ga(function=f,
           dimension=2,
           variable_type='real',
           variable_boundaries=varbound,
           algorithm_parameters=params
)

model.run()
convergence = model.report
solution = model.output_dict
print(solution['variable']) # x, y の最適値
print(solution['function']) # x, y の最適値での関数の値

■実行結果
 Average time of function evaluating (secs): 0.00015092323999997824
                                                                                                                                                                   
 The best found solution:
 [2.99003011 6.99942143]

 Objective function:
 -1.999900266599648

 Used generations: 101
 Used time: 0 seconds
[2.99003011 6.99942143]
-1.999900266599648

ほぼ (3, 7) が得られています。

.bash_profile での pyenv の設定内容

2022-03-19 12:16:24 | python
pyenv に関する設定は .bash_profile に以下の内容を記述します。
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"
eval "$(pyenv init -)"

eval "$(pyenv init --path)" を記述していなくて python が起動できませんでしたが、
これを記述したことで起動できるようになりました。

pip での No module named '_ctypes' への対処方法

2022-03-19 12:03:17 | python
pip でパッケージをインストールする際に以下のエラーが出力される場合の対処方法のメモ。
ModuleNotFoundError: No module named '_ctypes'


libffi-devel をインストールして python をインストールし直すと、このエラーは解消されます。
以下は、python-3.9.7 の場合です。
pyenv uninstall 3.9.7
sudo yum install libffi-devel
pyenv install 3.9.7


pillow で avif 形式の画像を処理できるようにする方法

2022-03-18 21:04:06 | python
pillow で avif 形式の画像を処理できるようにする方法のメモ。

pillow-avif-plugin をインストールします。
pip install pillow-avif-plugin


python プログラム内で pillow-avif-plugin を import すると、
pillow で avif 形式の画像を処理できるようになります。
import pillow_avif
from PIL import Image
...


pyocr による文字認識

2022-03-18 20:56:42 | python
pyocr で文字認識を行う方法のメモ。

まず、必要なライブラリ等をインストールします。
■leptonica のインストール
leptonica のページで rpm の URL を確認します。
https://centos.pkgs.org/8/centos-appstream-x86_64/leptonica-1.76.0-2.el8.x86_64\
.rpm.html


rpm をインストールします。
wget https://vault.centos.org/centos/8/AppStream/x86_64/os/Packages/leptonica-1\
.76.0-2.el8.x86_64.rpm
sudo rpm -ivh leptonica-1.76.0-2.el8.x86_64.rpm


■tesseract のインストール
sudo yum install tesseract tesseract-langpack-jpn.noarch


■pyocr のインストール
pip install pyocr


■プログラム
pyocr を用いた文字認識のサンプルプログラムです。
引数に画像ファイル名を指定すると、画像中のテキストを出力します。
import sys
from PIL import Image
import pyocr.builders

def main():
    img_file = sys.argv[1]

    tool = pyocr.get_available_tools()[0]
    img = Image.open(img_file)
    txt_bldr = pyocr.builders.TextBuilder()
    text = tool.image_to_string(img, lang='jpn', builder=txt_bldr)
    print(text)

    return 0

if __name__ == '__main__':
    res = main()
    exit(res)



TypeScriptでライブラリのパスに @ を使えるようにする方法

2022-03-17 23:46:25 | Node.js
TypeScriptでライブラリのパスに @ を使えるようにする方法のメモ。
tsconfig.json で以下のように paths を設定します。
{
  "compilerOption": {
    ...,
    "paths": {
      "@/*": ["./*"],
    },
    ...
}

ts-node で実行する ts ファイルを指定する際にコマンドラインオプションを指定します。
ts-node -r tsconfig-paths/register {TypeScriptファイル.ts}


apache で 403 Forbidden になる場合の対処方法

2022-03-15 23:52:28 | linux
apache で公開したいファイルのパーミッションなどに問題はなく、
403 Forbidden になる場合に以下を実行することでエラーが解消しました。
■setenforce で permissive モードに変更
sudo setenforce 0

■setenforce は一次的な設定変更のため、/etc/selinux/config を変更
#SELINUX=enforcing
SELINUX=permissive


python で変数名の文字列でインスタンス変数にアクセス

2022-03-01 23:57:44 | python
python で変数名の文字列でインスタンス変数にアクセスする方法のメモ。

getattr(インスタンス, インスタンス変数名) で指定インスタンスのインスタンス変数の値を取得することができます。
また、setattr(インスタンス, インスタンス変数名, 値) でインスタンス変数に値を設定することができます。
class Test:
    def __init__(self):
        self.var1 = 'abc'
        self.var2 = 'def'

    def get(self, var):
        return getattr(self, var)

    def set(self, var, val):
        setattr(self, var, val)

test = Test()
test.set('var3', 'ghi')
print(test.get('var1'))
print(test.get('var2'))
print(test.get('var3'))

■実行結果
abc
def
ghi



split コマンドでのファイル分割

2022-03-01 23:39:45 | linux
split コマンドの実行方法のメモ。

テキストファイルを1000行ごとに分割し、通し番号のサフィックスにファイルを分割するには、
-l で行数を指定し、-d で通し番号での分割を指定します。
split -l 1000 -d text.txt text.txt.

■実行結果
text.txt.00
text.txt.01
text.txt.02
text.txt.03