windows 11, でWSLのUbuntuを起動しようとしたところ、以下のエラーが出た。

プロンプトの画面の[設定]を開く。

左側のUbuntu(アイコンがオレンジのほう)を選択し、「コマンドライン」の項目を開く。
内容を以下のように書き換える

後は保存をして、Ubuntuを開きなおす。
https://loumo.jp/archives/28998
なぜこうなった。原因がわからん。
%03dみたいなファイル名からIDを取り出したい。sscanfを使う場合、「%03d」だと、「0005」など、3桁でない番号を拾えないので、いっそ%dのほうがいい。
#include <iostream> int main() { std::string pattern = "myfile_%d.txt"; std::string fname = "myfile_002010.txt"; int id; sscanf(fname.c_str(), pattern.c_str(), &id); printf("%d\n", id); }
#include <iostream> #include <regex> int main() { std::string pattern = "myfile_(\\d+)\\.txt"; std::regex reg_fname(pattern); std::string fname = "myfile_0001.txt"; std::smatch match; if (std::regex_search(fname, match, reg_fname)) { if (match.size() >= 2) { int id = std::stoi(match[1].str().c_str()); } } }
使う側としては正規表現を知らないと分かりづらいので%dを含んだ文字列を正規表現に変換することを考える。
.や+などの記号をエスケープした後で、%dを\d+に置換する。
#include <iostream> #include <regex>
// 正規表現の特殊文字をエスケープする関数 std::string escapeRegexSpecialCharacters(const std::string& str) { // 正規表現の特殊文字を定義 std::regex special_chars(R"([.^$*+?{}[\]()|\\])"); // 各特殊文字をエスケープシーケンスに置き換える return std::regex_replace(str, special_chars, R"(\$&)"); }
// パターンを正規表現に変換する関数 std::string convertPatternToRegex(const std::string& pattern) { std::string regex_pattern; // この処理により、 // "my+file_%d.txt" → "my\+file_%d\.txt" // のように、特殊文字をエスケープした文字列になる regex_pattern = escapeRegexSpecialCharacters(pattern); // %d または %0xd (例: %05d) を正規表現パターンに置換 // この処理により、 // "my\+file_%d\.txt" → "my\+file_(\d+)\.txt" std::regex d_pattern(R"(%\d*d)"); regex_pattern = std::regex_replace(regex_pattern, d_pattern, R"((\d+))"); return regex_pattern; }
int main() { // ファイル名のパターン std::string pattern = "my+file_%d.txt"; // ファイル名のパターンを正規表現に変換 std::string reg_pattern = convertPatternToRegex(pattern); std::regex regexpattern = std::regex(reg_pattern); // このファイル名から番号を取り出す std::string fname = "my+file_002010.txt"; std::smatch match; if (std::regex_search(fname, match, regexpattern)) { if (match.size() >= 2) { int id = std::stoi(match[1].str().c_str()); std::cout << id << std::endl; } } }
WSL2上でDockerのUbuntuを使っていると日本語が表示できない。これを解決する。
Before

After

以下で locale -a を行ってみる。日本語ロケールが存在しない。

まず言語パックをインストール
apt update
apt install language-pack-ja
そのあと、
設定が終わったら、LANGに言語を設定するため、~/.bashrc を編集する。
で、ファイルの最後に
終わったら
これで ls などすると日本語表示ができる。
#include <iostream> //VTK_MODULE_INITに必要 #include <vtkAutoInit.h> #include <vtkSmartPointer.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> // コールバック関数を使用するのに必要 #include <vtkCallbackCommand.h> //必須 VTK_MODULE_INIT(vtkRenderingOpenGL2); VTK_MODULE_INIT(vtkInteractionStyle);
// コールバック関数に渡すデータ struct MyData { std::string text; int counter; };
// タイマーのコールバック関数 void MyTimerCallbackFunction(vtkObject* caller, long unsigned int eventId, void* clientData, void* callData) { MyData* data = static_cast<MyData*>(clientData); // タイマーイベントが発生したことを確認する std::cout << data->text << " " << data->counter << std::endl; data->counter++; // 画面更新 auto interactor = static_cast<vtkRenderWindowInteractor*>(caller); interactor->Render(); }
int main(int /*argc*/, char** /*argv*/) { ////////////////////////////////////// auto renderer = vtkSmartPointer<vtkRenderer>::New(); renderer->ResetCamera(); ////////////////////////////////////// auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); auto renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); renderWindow->AddRenderer(renderer); renderWindow->SetInteractor(interactor); renderWindow->Render(); //////////////////////////////////////
// タイマーに渡す構造体の作成 MyData callbackData{ "Counter:",0 }; // タイマー作成 auto timerCallback = vtkSmartPointer<vtkCallbackCommand>::New(); timerCallback->SetCallback(MyTimerCallbackFunction); // コールバック関数を設定 timerCallback->SetClientData(&callbackData); // コールバック関数に渡すデータを設定 interactor->AddObserver(vtkCommand::TimerEvent, timerCallback); // タイマーイベントにコールバック関数を設定 interactor->Initialize(); interactor->CreateRepeatingTimer(100); // 100msごとにタイマーイベントを発生させる
////////////////////////////////////// interactor->Start(); //イベントループへ入る return 0; }
以前、UnicodeStringを使用したが、これは内部に文字列をコピーしてしまうので、文字列の管理をicuにやらせないのであれば効率が悪い。ubrk_openでブレークイテレータを取得すると、元の文字列に対して操作できる。
#include <iostream> #include <unicode/ubrk.h> #include <unicode/ustring.h> #include <vector> #include <fstream> // 要リンク #pragma comment(lib, "icuuc.lib") struct Grapheme { int32_t start; int32_t end; };
std::vector<Grapheme> createGraphemeList(const char16_t* text,const size_t length) { UErrorCode status = U_ZERO_ERROR; std::vector<Grapheme> graphemes; // イテレータ作成 UBreakIterator* bi = ubrk_open(UBRK_CHARACTER, "ja_JP", nullptr, 0, &status); if (U_FAILURE(status)) { return std::vector<Grapheme>(); // エラーが発生 } // テキストを設定 ubrk_setText(bi, (const UChar*)text, length, &status); // ubrk_setText(bi, (const UChar*)text, -1, &status);// null終端の場合は -1 を指定できる if (U_FAILURE(status)) { ubrk_close(bi); return std::vector<Grapheme>(); // エラーが発生 } // 最初の書記素の位置を取得 int32_t start = ubrk_first(bi); int32_t end; // 書記素リストを作成 while ((end = ubrk_next(bi)) != UBRK_DONE) { graphemes.push_back(Grapheme{ start, end }); start = end; } // 終了処理 ubrk_close(bi); return graphemes; }
int main() { // 日本語ロケール setlocale(LC_ALL, "japanese"); std::u16string u16str = u"あいうえお"; std::vector<Grapheme> glist = createGraphemeList(u16str.data(),u16str.length()); for(size_t i = 0; i < glist.size(); i++) { size_t length = glist[i].end - glist[i].start; std::wstring u16w( (wchar_t*)u16str.data()+ glist[i].start, length); std::wcout << u16w;// 一文字ずつ表示 std::wcout << "( " << glist[i].start << L" " << glist[i].end << " )" << std::endl; } }
結合文字はWindowsのコンソールで扱うとうまく表示できないので、代わりにテキストファイルとして出力して動作確認する。
int main() { // 日本語ロケール setlocale(LC_ALL, "japanese"); std::u16string u16str = u"あい👨👩👧👦うえお"; // 👨👩👧👦 絵文字(結合文字) std::vector<Grapheme> glist = createGraphemeList(u16str.data(), u16str.length()); // バイナリ出力 std::ofstream out("grapheme.txt", std::ios_base::binary); for (size_t i = 0; i < glist.size(); i++) { size_t length = glist[i].end - glist[i].start; out.write((const char*)(u16str.data() + glist[i].start), length * 2);// 一文字出力 out.write("\n", 2); } }
確認には、Wordを開き、テキストファイルを開く際の文字コードをUnicodeに指定するのが良い。

VC++のC++言語標準をISO C++ 20に設定したところ、以下のエラーが出た。
Open3DConfig.h を確認してみると、バージョン 0.9.0.0だった。
#define OPEN3D_VERSION "0.9.0.0"
調べた限りまともな対処法がないので、Open3Dを最新版にする。
公式 https://www.open3d.org/ の下のほうへ行き、0.18.0を選択する。

展開してC++20で使用。
そのままだとC4996が出るので、#pragma warning(disalbe:4996) を入れる。
あるいは
_SILENCE_CXX20_IS_POD_DEPRECATION_WARNING
_SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING
を定義する。
#pragma warning(disable:4996) #if defined(_DEBUG) #pragma comment(lib,"C:\\libraries\\Open3D-0.18.0\\debug\\lib\\Open3D.lib") #else #pragma comment(lib,"C:\\libraries\\Open3D-0.18.0\\release\\lib\\Open3D.lib") #endif #include <Open3D/Open3D.h> #include <iostream> int main() { std::string filename = "bunny.ply"; auto mesh = open3d::io::CreateMeshFromFile(filename); auto pcd = open3d::io::CreatePointCloudFromFile(filename); }
以下のように、StatisticalOutlierRemovalを使ってみると、Eigenのコード内で、aligned_freeで例外が発生する。
#include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/features/normal_3d.h> #include <pcl/filters/statistical_outlier_removal.h> pcl::PointCloud<pcl::PointXYZ>::Ptr create_cloud() { // 点群データの生成 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>()); cloud->width = 1000; cloud->height = 1; cloud->is_dense = false; cloud->points.resize(cloud->width * cloud->height); for (size_t i = 0; i < cloud->points.size(); ++i) { cloud->points[i].x = 1024 * rand() / (RAND_MAX + 1.0f); cloud->points[i].y = 1024 * rand() / (RAND_MAX + 1.0f); cloud->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f); } return cloud; }
int main(int argc, char** argv) { auto cloud = create_cloud(); pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>); pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor; sor.setInputCloud(cloud); sor.setMeanK(50); sor.setStddevMulThresh(1.0); sor.filter(*cloud_filtered); return 0; }
C:/Program Files/PCL 1.14.1/3rdParty/Eigen3/include/eigen3/Eigen/src/Core/util/memory.h
ファイル内、以下の部分で例外が発生。

/** \internal Frees memory allocated with aligned_malloc. */ EIGEN_DEVICE_FUNC inline void aligned_free(void *ptr) { #if (EIGEN_DEFAULT_ALIGN_BYTES==0) || EIGEN_MALLOC_ALREADY_ALIGNED EIGEN_USING_STD(free) free(ptr); #else handmade_aligned_free(ptr); #endif }
C/C++ → コード生成 → 拡張命令セットを有効にする → Advanced Vector Extensions (X86/X64) (/arch:AVX)
に設定

VTKのvtkSmartPointerは参照カウンタ付きだが、vtkWeakPointerもある(初めて知った)。
まず以下は、vtkSmartPointerを使った場合で、ポインタをコピーするたびに参照カウンタが増え、ポインタにnullptrを代入して無効化することで参照カウンタが減ることを確認する。
vtkSmartPointer<vtkActor> actor1 = vtkSmartPointer<vtkActor>::New(); std::cout << "actor1 reference count: " << actor1->GetReferenceCount() << std::endl; vtkSmartPointer<vtkActor> actor2 = actor1; std::cout << "actor2 reference count: " << actor2->GetReferenceCount() << std::endl; actor1 = nullptr;// actor1を無効化 std::cout << "Delete" << std::endl; // ここは通らない if(actor1) std::cout << "actor1 reference count: " << actor1->GetReferenceCount() << std::endl; if(actor2) std::cout << "actor2 reference count: " << actor2->GetReferenceCount() << std::endl;
vtkWeakPointer<vtkActor> weak_actor; // WeakPointerを定義
{ vtkSmartPointer<vtkActor> actor1 = vtkSmartPointer<vtkActor>::New(); std::cout << "actor1 reference count: " << actor1->GetReferenceCount() << std::endl; weak_actor = actor1;// actor1 を弱参照 参照カウンタは増えない std::cout << "weak_actor reference count: " << weak_actor->GetReferenceCount() << std::endl; vtkSmartPointer<vtkActor> actor2 = actor1; std::cout << "actor2 reference count: " << actor2->GetReferenceCount() << std::endl; actor1 = nullptr; std::cout << "Delete" << std::endl; // ここは通らない if (actor1) std::cout << "actor1 reference count: " << actor1->GetReferenceCount() << std::endl; if (actor2) std::cout << "actor2 reference count: " << actor2->GetReferenceCount() << std::endl; }
if (weak_actor) { // ここは通らない std::cout << "actor1 reference count: " << weak_actor->GetReferenceCount() << std::endl; } else { // こちらを通る std::cout << "actor is deleted" << std::endl; }
gumbo-parseがどのようにデータを保持しているのかをチェックするためのコード。
タグはenumで区別するため、タグ名は保持していない。<から始まっていることを利用してstd::regexでタグ名を取得している。
#include <iostream> #include <fstream> #include <sstream> #include <regex> #include <gumbo.h>
std::string getTagName(std::string str) { // HTMLのタグ名を取得する関数 // タグは< > で囲まれているが、attribute等があるかもしれないので // < スペース 文字列 という構造になっている部分の文字列部分だけを取り出す std::regex tagPattern("<\\s*([^ >]+)\\s*"); std::smatch matches; std::regex_search(str, matches, tagPattern); return matches[1].str(); }
void myTraceCore(const GumboNode* node, const char* src) { switch (node->type) { case GUMBO_NODE_ELEMENT: { // 要素開始位置 const char* tag_start = node->v.element.original_tag.data; // 要素終了位置 const char* tag_end = node->v.element.original_end_tag.data; std::string tagname; // タグ名を抽出 tagname = getTagName(tag_start); std::cout << "tag: '" << tagname << "'" << std::endl; // 子要素一覧へアクセス const GumboVector* children = &node->v.element.children; // 子要素がある場合 if (children->length > 0) { for (unsigned int i = 0; i < children->length; ++i) { const GumboNode* node = static_cast<GumboNode*>(children->data[i]); myTraceCore(node, src); } } // タグ名を抽出 tagname = getTagName(tag_end); std::cout << "tag: '" << tagname << "'" << std::endl; break; } case GUMBO_NODE_TEXT: // テキストノードの場合 std::cout << "text: '" << node->v.text.text << "'" << std::endl; break; case GUMBO_NODE_WHITESPACE: // 空白ノードの場合 std::cout << "whitespace: '" << node->v.text.text << "'" << std::endl; break; default: std::cout << "others: '" << node->v.text.text << "'" << std::endl; break; } }
void myTrace(std::string html) { // Gumboでパース GumboOutput* output = gumbo_parse(html.c_str()); // 自作関数の本体呼び出し myTraceCore(output->root,html.c_str()); // GumboOutputの解放 gumbo_destroy_output(&kGumboDefaultOptions, output); } int main() { std::string html = R"( <!DOCTYPE html> <html> <head> <title>The Title</title> </head> <body> <h1>Test</h1> </body> </html> )"; myTrace(html); }
tag: 'html'
tag: 'head'
whitespace: '
'
tag: 'title'
text: 'The Title'
tag: '/title'
whitespace: '
'
tag: '/head'
whitespace: '
'
tag: 'body'
whitespace: '
'
tag: 'h1'
text: 'Test'
tag: '/h1'
whitespace: '
'
tag: '/body'
tag: '/html'
node->typeがGUMBO_NODE_ELEMENTの時は、属性を取得できる。
#include <iostream> #include <fstream> #include <sstream> #include <regex> #include <gumbo.h>
// 要素の属性を取得する関数 void myAttributes(const GumboNode* node) { if (node->type != GUMBO_NODE_ELEMENT) { return; } // 要素の属性を取得 const GumboVector* attributes = &node->v.element.attributes; // 属性リストへアクセス for (unsigned int i = 0; i < attributes->length; ++i) { GumboAttribute* attr = (GumboAttribute*)attributes->data[i]; std::cout << " "; std::cout << " " << attr->name << " : " << attr->value << std::endl; } }
void myTraceCore(const GumboNode* node, const char* src) { switch (node->type) { case GUMBO_NODE_ELEMENT: {
/* ... */ myAttributes(node); // 要素の取得
/* ... */ break; } /* ... */ } }
int main() { std::string html = R"( <!DOCTYPE html> <html> <head> <title id = "bodyid" style="color:red;">The Title</title> </head> <body> <h1>Test</h1> </body> </html> )"; myTrace(html); }
id : bodyid
style : color:red;
HTMLを扱う方法を探している。gumbo-parserはgoogleが公開したApache-2.0 licenseのパーサー。
ソースコードをGitHubからダウンロード・展開する。
https://github.com/google/gumbo-parser
CMake不要。.cファイルをコピーしてプロジェクトに加える。
注意点として、windowsにはstrings.hが存在しない。
追加のインクルードディレクトリ:
visualc/includeにはstrings.hが入っている。
・gumbo-parser-master/src
・gumbo-parser-master/visualc/include
プロジェクトへ追加
src/*.c ファイルをプロジェクトへ追加する。
attribute.c
char_ref.c
error.c
parser.c
string_buffer.c
string_piece.c
tag.c
tokenizer.c
utf8.c
util.c
vector.c
・gumbo_parse関数でパースを行う。
・GumboVectorはGumboNodeの配列となっている。
・node->v.element.children->data から子ノードにアクセスできる
#include <iostream> #include <fstream> #include <sstream> #include <gumbo.h>
std::unique_ptr<std::string> getTitleCore(const GumboNode* node) { // ノードがHTML要素の場合だけ処理 if (node->type == GUMBO_NODE_ELEMENT) { // titleタグの場合 if (node->v.element.tag == GUMBO_TAG_TITLE) {
// 子要素一覧へアクセス const GumboVector* children = &node->v.element.children; // 子要素がある場合 if (children->length > 0) { // 子要素の先頭を取得 const GumboNode* child = static_cast<GumboNode*>(children->data[0]); if (child->type == GUMBO_NODE_TEXT) { return std::make_unique<std::string>(child->v.text.text); } }
}
// titleタグ以外の場合、このタグの子要素を全て調査。それを再帰的に行う else {
const GumboVector* children = &node->v.element.children; for (unsigned int i = 0; i < children->length; ++i) { std::unique_ptr<std::string> result = getTitleCore(static_cast<GumboNode*>(children->data[i])); if (result != nullptr) { return result; } }
}
} return nullptr; }
std::unique_ptr<std::string> getTitle(std::string html) { // Gumboでパース GumboOutput* output = gumbo_parse(html.c_str()); // タイトルを取得する自作関数の本体呼び出し std::unique_ptr<std::string> result = getTitleCore(output->root); // GumboOutputの解放 gumbo_destroy_output(&kGumboDefaultOptions, output); return result; }
int main() { std::string html = R"( <html> <head> <title>The Title</title> </head> <body> <h1>Test</h1> </body> </html> )"; std::unique_ptr<std::string> mytitle = getTitle(html); if (mytitle != nullptr) { std::cout << *mytitle << std::endl; } else { std::cout << "** No title **" << std::endl; } }