スキップしてメイン コンテンツに移動

投稿

ラベル(Code Tips)が付いた投稿を表示しています

C#でUDPデータ受信

受信側サンプルコード // 基本 var receiveIpAddress = "127.0.0.1" ; var local = new IPEndPoint ( IPAddress . Parse ( receiveIpAddress ) , Port ) ; var remote = new IPEndPoint ( IPAddress . Any , 8006 ) as EndPoint ; socket . Bind ( local ) ; var buffer = new byte [ 3 ] ; while ( true ) { Console . WriteLine ( "Start Receiving" ) ; // var length = socket.ReceiveFrom(buffer, ref remote); var length = socket . Receive ( buffer ) ; var requiredBuffer = new byte [ length ] ; Buffer . BlockCopy ( buffer , 0 , requiredBuffer , 0 , length ) ; var data = Encoding . UTF8 . GetString ( requiredBuffer ) ; Console . WriteLine ( "data received: " + data ) ; } 受信側コードの注意点 bufferの配列サイズがdatagramサイズより小さいと、下記のようなエラーが出る System.Net.Sockets.SocketException (10040): A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datag

C#でenumに定義された値の一覧を取得する方法

下記のコードでenumに定義された値の一覧を取得できます。 // MyEnumの部分を一覧を取得したいenumに書き換えてください。 var enums = Enum . GetValues ( typeof ( MyEnum ) ) . Cast < MyEnum > ( ) ; // ループしてプリントしてみる。 foreach ( var @ enum in enums ) { Console . WriteLine ( @ enum . ToString ( ) ) ; } ちなみにコード内の「@」はC#の予約語を変数名で使えるようにするためのものです。 さらに下記のようGenericsを使って一般化したメソッドを定義できます。 public static IEnumerable < T > IterateEnum < T > ( ) where T : Enum = > Enum . GetValues ( typeof ( T ) ) . Cast < T > ( ) ;

C#でMarshalクラスを使ってbyte配列から構造体を生成する方法

C#の通信プログラムでbyte配列を読み込んで、構造体(struct)を生成したいときにサンプルコードの紹介です。 Genericsを使って任意の構造体をbyte配列から生成できるようにしています。 public static T ReadAsStruct < T > ( this byte [ ] bytes , int startIndex ) where T : struct { // GCHandle.Allocクラスを使ってメモリ上のデータがガーベッジコレクタの対象にならないようにする。 var handle = GCHandle . Alloc ( bytes , GCHandleType . Pinned ) ; try { // Marshalクラスのメソッドを使って、byte配列のIntPtr(ポインタ)を取得。 var ptr = Marshal . UnsafeAddrOfPinnedArrayElement ( bytes , startIndex ) ; // IntPtrで指定した位置のbyte配列から構造体を生成。 return ( T ) Marshal . PtrToStructure ( ptr , typeof ( T ) ) ; } finally { // 重要!!必ずGCHandleを開放して、再びbyte配列がガーベッジコレクタの対象になるようにする。 handle . Free ( ) ; } } ちょっと考察 ■ パフォーマンス 毎回GCHandle.Alloc, Freeを行う分、パフォーマンスのオーバーヘッドが発生します。パフォーマンスが気になる場合は、GCHandle.Alloc, Freeの間に、複数の構造体を生成するようにするとよいかもしれません。 ■ 他の書き方 startIndexがいつもゼロの場合、下記の部分は、 var ptr = Marshal . UnsafeAddrOfPinnedArrayElem

C#でbyte orderを反転する方法

UDPパケットの受信時に受信したデータのbyte orderを反転する必要がある場合があります。そんな場合に使えるbyte orderを反転するC#のコードの紹介です。 処理の流れは下記になります。 BitConverter.GetBytesメソッドを使って、値のbyte配列表現を取得。 Array.Reverseメソッドでbyte配列の順番を反転する。 BitConverter.ToXXXメソッドで元の値の型に戻す。 ushort, uint, int, ulong, float, doubleなどの型についてコードを示します。 public static void ReverseBytes ( this ref ushort value ) { var source = BitConverter . GetBytes ( value ) ; Array . Reverse ( source ) ; value = BitConverter . ToUInt16 ( source , 0 ) ; } public static void ReverseBytes ( this ref uint value ) { var source = BitConverter . GetBytes ( value ) ; Array . Reverse ( source ) ; value = BitConverter . ToUInt32 ( source , 0 ) ; } public static void ReverseBytes ( this ref int value ) { var source = BitConverter . GetBytes ( value ) ; Array . Reverse ( source ) ; value = BitConverter . ToInt32 ( source , 0 ) ; } public static void ReverseBytes ( this ref ulong value ) { v

firestoreでAuto Incrementフィールドを作成

FirestoreでAuto Increment Fieldを作成 Firestoreで連番となるフィールドの作成方法を紹介します。 肝はFirestoreのtransactionを使って原子性(Atomicity)、一貫性(Consistency)、独立性(Isolation)を保証することです。 汎用的に使えるgenerateSequenceNumber関数を作成してみました。 manage_collection: 連番を生成するターゲットcollectionを管理するcollection名 target_collection: 連番を生成するターゲットとなるcollection名 numberField: 連番を生成したいフィールド名 を渡して使います。 function generateSequenceNumber ( db , manage_collection , target_collection , numberField ) { const docRef = db . collection ( manage_collection ) . doc ( target_collection ) ; return db . runTransaction ( ( transaction ) => { return transaction . get ( docRef ) . then ( ( doc ) => { if ( ! doc . exists ) { transaction . set ( docRef , { [ numberField ] : 1 } ) ; return 1 ; } const newNumber = typeof doc . data ( ) [ numberField ] === 'undefined' ? 1 : doc . data ( ) [ numberField ] + 1 ; await transaction . update ( docRef , { [ numberField

PHPのエラーレベル定数からエラー文字列を返すコード

PHPで定義されているエラー定数(int値)からエラー定数の文字列を返すコードです。 PHPのライブラリで定義されている情報だけで、キーが「エラー定数のint値 」値が「エラー文字列」となる連想配列を生成しています。 // 定義済みの定数を取得 $allConstants = get_defined_constants ( true ) ; // "Core"カテゴリに入っていて"E_"から始まる定数のみ取得 $errorConstants = array_filter ( $allConstants [ "Core" ] , fn ( $key ) = > strncmp ( $key , "E_" , 2 ) === 0 , ARRAY_FILTER_USE_KEY ) ; // エラー定数のint値 -> エラー文字列になるように連想配列を逆転 $errorCodeToString = array_flip ( $errorConstants ) ; // 使い方の例 echo $errorCodeToString [ E_COMPILE_ERROR ] ;

JavascriptのObject Literalを使った条件分岐

条件分岐を簡潔に書きたい! 条件分岐をする場合、通常はif~else文やswitch~case文を使うことが一般的ですが、Object Literalを活用すると簡潔にコードを書くことできる場合があります。Object Literalを利用するのは、ちょうどPHPのarray、JavaのMap、C#のDictionaryなどの連想配列を利用するイメージが近いと思います。 switch~case文とObject Literalを使った場合のコード例をいくつか示していきます。 switch~case文とローカル変数を使った場合 function GetStockCode_LocalVariable ( makerName ) { let code = "" ; switch ( makerName ) { case "Asus" : code = "2557" ; break ; case "MSI" : code = "2377" ; break ; default : throw new Error ( "unsupported maker: " + makerName ) ; } console . log ( code ) ; } 一般的な書き方ですが、下記の短所があります。 mutableなローカル変数のcodeを定義しなければならない。 switch~caseのキーワードやbreakキーワードが何度も出現し、重要な部分がわかりにくい switch~case文と即時実行関数式(Immediately Invoked Function Expression)を使った場合 function GetStockCode_IIFE ( makerName ) { const code = ( ( ) => { switch ( m

JavaのServlet内で他のURLから取得したデータをそのまま出力するコード

JavaのServlet内で他のURLからデータを取得してそのまま、レスポンスを出力するためのコードサンプルです。 使っているのはJavaの標準ライブラリのみなので、移植性は高いと思います。googleの提供しているライブラリやApacheのcommonsのライブラリを使うともう少しコード量は減らせると思います(特に汎用的なcopyメソッドの部分)。 import java.io.IOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; public class ServletUtils { private static final int _20K_BYTES = 20480; public static void fetchUrlAndDirectlyRespond(HttpServletResponse resp, String contentType, String urlStr) throws MalformedURLException, IOException, URISyntaxException { URL url = new URI(urlStr).toURL(); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoOutput(true); connection.setRequestMethod("GET"); connection.connect(); ServletOutput

JavaでTimeZoneを指定して日付をフォーマットする方法

国際的に使われるソフトウェアを開発している場合、日付のタイムゾーンを意識しなければならないことがあると思います。 JavaではZoneIdクラスとZonedDateTimeクラスを利用することで簡単に指定することができます。 下記にAsia/Tokyoのタイムゾーンを指定して、7日前の日付をuuuuMMddHHmmフォーマット(分単位まで表示。例: 2021年2月13日21時34分ならば202102132134)で出力するサンプルコードを示します。 private static final ZoneId TIMEZONE_TOKYO = ZoneId.of("Asia/Tokyo"); private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("uuuuMMddHHmm"); String date_7_days_before = ZonedDateTime.now(TIMEZONE_TOKYO).plusMinutes(-7).format(DATETIME_FORMATTER); System.out.println(date_7_days_before);

Webのリクエストのパラメタを指定したパラメタ順でソートする方法(PHP)

Webリクエストのパラメタを指定したパラメタ名の順でソートするプログラムを書いてみました。 プログラム自体は汎用的なので、パラメタのソートに限らず、それ以外でも利用可能です。 <?php class ParameterSorter { private $sortOrder; // パラメタのソート順を指定 public function __construct($sortOrder) { $this->sortOrder = array_flip($sortOrder); $this->max = count($sortOrder); } // uksortを使って指定されたパラメタ順でソート // $sortOrderのキーをパラメタ名に変換して、uksortを使うのは性能を上げるためです。 // ソート順が指定されていないパラメタは、ソート順が指定されたパラメタの後になるように実装しています。 public function sort(&$parameters) { uksort($parameters, function($a, $b){ return ($this->sortOrder[$a] ?? $this->max) - ($this->sortOrder[$b] ?? $this->max); }); } // PHPのuksortは安定でない(同順位の場合もとの順序が保存されない)らしいので、元の順序を確実に保証するバージョンも作成しました。 public function stableSort(&$parameters) { $originalOrder = array_flip(array_keys($parameters)); uksort($parameters, function($a, $b) use($originalOrder){ $compared = ($this->sortOrder[$a]

テキストをNグラムに分割するJavaプログラム

与えられたテキストをNグラム(n-gram)で分割するJavaプログラムです。 Javaの標準ライブラリのjava.util.ArrayList、java.util.Listを使っています。 public static List<String> splitByNGram(String src, int n) { List<String> chunks = new ArrayList<>(); for(int start = 0, len = src.length(); start < len; start++) { int end = start + n; chunks.add(src.substring(start, end < len ? end : len)); } return chunks; }

Javaで平仮名をカタカナに変換するプログラム

Javaで平仮名をカタカナに変換するプログラムです。 public static String conbertHiragana2Katakana(String str) { int delta = 'ア' - 'あ'; StringBuilder buf = new StringBuilder(str.length()); for (int i = 0; i < str.length(); i++) { char code = str.charAt(i); Character.UnicodeBlock block = Character.UnicodeBlock.of(code); if (block != null && block.equals(Character.UnicodeBlock.HIRAGANA)) { buf.append((char)(code + delta)); } else { buf.append(code); } } return buf.toString(); }

複数の配列から要素を1つずつ選んで、すべての組み合わせを生成するPHPのプログラム

複数の配列から、要素を1つずつ選んですべての組み合わせを生成するプログラムをPHPで書いてみました。 ただし、組み合わせをすべて生成すると組み合わせ爆発を起こす可能性がありますので、使う際は本当に必要か慎重に検討してください。 <?php function iterateAllCombinations($sets, callable $callback) { $indexToKey = array_keys($sets); self::iterateAllCombinationsRecursive($sets, count($sets), $indexToKey, $callback, 0, []); } // 再帰的に呼ぶための関数本体 function iterateAllCombinationsRecursive($sets, $countOfSets, $indexToKey, callable $callback, $n, $generatedCombination) { if($n >= $countOfSets) { // この部分で生成された組み合わせを引数として、callbackが毎回呼ばれる。 $callback($generatedCombination); return; } $keyOfSet = $indexToKey[$n]; foreach($sets[$keyOfSet] as $e) { $generatedCombination[$keyOfSet] = $e; self::iterateAllCombinationsRecursive($sets, $countOfSets, $indexToKey, $callback, $n+1, $generatedCombination); } } 下記は、$callback内で生成された組み合わせをため込んだ場合の使用例になります。 <?php // 組み合わせを生成したい3つの配列 $sets = [ 'key1' => ['A', 'B',

PHPで呼び出されたメソッド階層を取得

デバッグ目的で、メソッドの呼び出された階層を取得したいときがあると思います。 PHPでは、Exceptionを生成してException::getTraceAsStringメソッドでStack Traceを取得する方法が簡単です。 下記にコードを示します。 <?php function extractTrace($endLineNumber, $startLineNumber=1) { $stackTrace = (new \Exception())->getTraceAsString(); $start = strpos($stackTrace, "#".$startLineNumber); $end = strpos($stackTrace, "\n#".($endLineNumber+1)); if($start !== false || $end !== false) { return substr($stackTrace, $start, ($end - $start + 1) ?: strlen($stackTrace)); } return $stackTrace; } 簡単な解説です。 引数でStack Traceを取得する範囲を指定できるようにしています。 \Exceptionを生成した個所からStack Traceが生成されるので、Stack Traceの1行目の"#0"の部分を取り除くためにデフォルトでは、$startLineNumberを1に設定しています。 $stackTrace = (new \Exception())->getTraceAsString();の部分を外部から引数で渡すのもありですが、毎回同じ処理を書く必要があるので、extractTrace関数内部に入れてあります。

PDOで指定したクラスにデータを割り当てて取得する方法

PDOで指定したクラスにデータを割り当てて取得するには、\PDO::FETCH_CLASSをMyPdo::fetch, MyPdo::fetchAllメソッドの引数に指定すれば簡単に実現できます。 通常はPDO::FETCH_ASSOCを指定して、array形式でデータを取得する方が手軽ですが、classでデータを扱うと、下記のメリットがあります。 arrayよりもclassでデータ取得した方がメモリ使用量が少ない arrayよりも、どんなデータを扱っているのかが明確になる それでは、\PDO::FETCH_CLASS使用例を下記に示します。 <?php $sql = <<<EOF SELECT id, name, weight, price FROM table_prodict EOF; $conn = new MyPdo(....); $conn->prepare($sql); $stmt = $conn->execute(); // クラスは第2引数で指定 $stmt->fetchAll(\PDO::FETCH_CLASS, Product::class); Porductクラスは下記を想定しています。 <?php class Product { public $id; public $name; public $weight; public $price; } \PDO::FETCH_CLASSの挙動についての補足です。 クラスを特に指定しないと、取得したカラムに対応したプロパティを持ったstdClassのインスタンスで結果が返ってきます。 指定したクラスに、クエリから取得したカラムに対応したプロパティがない場合(例えば、上記のProductカラムに$priceプロパティがない場合)は、動的にプロパティが定義されて取得したデータがセットされます。 \PDO::FETCH_PROPS_LATEを使うとプロパティにデータをセットする前に、クラスのコンストラクタが呼ばれます。クラスの事前処理が必要な場合に指定すると便利です。 クラスのプロパティ定義がprivateでも正しくデータはセットされます😲

PHPでarrayをgroup byする関数

通常はデータベース上でSQLを使ってgroup byをすれば十分ですが、下記のような場合プログラム側で実施するのもありです。 DBから取得したデータから別の複数の集計(group by)結果を得ることができる DBのgroup byの実行に時間がかかり、何度も似たような集計をDBに計算させるのは実行コスト(時間、CPU負荷)が高い 今回は汎用的にPHP側でgroup byを実行できるコードを書いてみました。 任意の複数フィールドで集計できるようにするため、多少コードが複雑になっています。 またkeyのencode/decode部分の処理で多少無駄があります。 <?php function groupBy(array $rows, array $groupByFields, callable $aggregate) { $groupByFieldsAsKey = array_flip($groupByFields); $map = []; foreach($rows as $row) { // キーになるならどんな関数でもOK。ここではjson_encodeを採用 $key = json_encode(array_intersect_key($row, $groupByFieldsAsKey)); $aggregatedRow = &$map[$key] ?? []; $aggregate($aggregatedRow, $row); } $result = []; foreach ($map as $key => &$aggregatedRow) { // キーをデシリアライズして、フィールドと値を集計結果の行にコピー $keyValue = json_decode($key, true); foreach($groupByFields as $groupByField) { $aggregatedRow[$groupByField] = $keyValue[$groupBy

PHPのXMLReaderを使ったXMLの読み込み

はじめに PHPでXMLを読み込むには、通常はSimpleXMLElementを使えば十分です。 ただし、XMLが巨大でメモリを節約して処理する必要がある場合は、XMLのパーサーであるXMLReaderを使って処理する方法があります。 XMLReaderを使って読み込む際はXMLの構造をどうとらえるかによって、プログラムの書き方が変わるのと、毎回読み込みの方法をプログラムしなければならないのが欠点です。 今回は下記のサンプルXMLのproduct部分を読み込むXMLReaderのプログラムのサンプルを、XMLReaderの機能紹介も兼ねて、いくつか示します。 <?xml version="1.0" encoding="UTF-8"?> <products> <date type="1">20200414</date> <product> <maker>AMD</maker> <name>Ryzen 3400G</name> </product> <product> <maker>Intel</maker> <name>Core i9 9900K</name> </product> </products> サンプルプログラムでは、下記のPHPの配列形式を取得することを目標にします。 実際の用途ではXMLReaderを使ってXMLを読み込むと同時に、CSVファイルに出力するなどといった処理が考えられます。 この場合、メモリはXMLReader部分と、読み込み途中で一時的に保持しているデータのみで利用されるので、メモリの使用量は最低限に抑えることができます。 [ [ "maker"=> "AMD", "name"=> "Ryzen

PHPで空のディレクトリを再帰的にすべてたたどるプログラム

PHPで指定したディレクトリにある全ディレクトリ内の空ディレクトリをすべてたどるプログラムを書いてみました。 書いた動機としては、あるディレクトリ内にあるディレクトリをすべて削除したかったためです。 symbolic linkはファイルとして扱っているので無視されます。 <?php // $callbackの引数の$fileに、空ディレクトリの\SplFileInfoが渡されて呼ばれます。 function visitEmptyDirectoryRecursively($path, callable $callback) { $files = new \DirectoryIterator($path); $containsOnlyDirectory = true; /* @var $file \SplFileInfo */ foreach($files as $file) { if($file->isDot()) { continue; } else if($file->isDir()) { if(visitEmptyDirectoryRecursively($file->getRealPath(), $callback)) { $callback($file); } else { $containsOnlyDirectory = false; } } else { $containsOnlyDirectory = false; } } return $containsOnlyDirectory; } // 空ディレクトリをすべて削除する場合は、下記のようにして使います。 // permissionの関係でディレクトリを消すことができないなどのエラー処理が必要な場合は、

SQLで特定の文字を組み合わせたランダムな文字列を生成

簡易的な方法として「指定した文字列からランダムに1文字選ぶ」を必要な文字の長さ分concat関数でつなげれば実現できます。 1文字ずつ文字を選ぶので、あまり性能もよくない上、セキュリティ的な観点からのランダム性も担保されていないので、あくまで開発中に必要になった時に使う程度が無難だと思います。 下記に英数字大文字小文字を含んだランダムな3文字の文字列を生成するクエリを示します。 # RAND関数で指定した文字列からランダムに1文字選択。 # 下記の例の62の部分はa~z、A~Z、1~9の文字数の合計値を入れた結果 SELECT CONCAT( SUBSTRING('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', FLOOR(RAND() * 62 + 1), 1), SUBSTRING('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', FLOOR(RAND() * 62 + 1), 1), SUBSTRING('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', FLOOR(RAND() * 62 + 1), 1) ) AS random_string;