Summary_code
title: DVJS20_TABLE_key_value_pairs_via_RegExp_and_Obsidian_API_groupBy_Title => 0.To require the plugin admonition 1.To get key-value pairs via RegExp and Obsidian API 2.To group by h_row.Title 3.To display the result as a table
collapse: open
icon:
color:
```dataviewjs
// M11. define pages: gather all relevant pages
// #####################################################################
const pages = dv.pages(
'"100_Project/01_dataviewjs/01_by_example/Q27_Admonition/Q27_test_data"'
);
// M13. define regex: find the contents of a specifically formatted callout
// REGEX_CALLOUT_BOX_OF_ADMONITION
// input:
//
// ```ad-abstract
// title: Explain Recursion (5)
// area: General
// cover: ![|150](file:///E:/Q27_test_data_images/Q27_General01.jpg)
// For an explaition of recursion, please look up Recursion
// ```
//
// output:
// Title="Explain Recursion"
// Points="5"
// Area="General"
// Cover="![|150](file:///E:/Q27_test_data_images/Q27_General01.jpg)"
// Content="For an explaition of recursion, please look up Recursion\n"
//
// OS Abbreviation Escape sequence
// Windows : CR+LF \r\n
// UNIX : LF \n
// MAC : CR \r
//
// 1.Following Unix, Obsidian under different operating systems uses
// LF alone as a line terminator in a markdown file.
// 2.In other words, a markdown file created in Obsidian under different
// operating systems uses LF alone as a line terminator.
// 3.Howerver, a read-only markdown file with CR+LF(or CR) as a line
// terminator still keeps its original newline. Obsidian cannot transform
// a newline into LF because the file does not have write permission.
// 4.Therefore, if there is no read-only markdown file,
// uses LF alone like `let regex_Newline = /(?=\n)/g;`.
// Otherwise, uses `let regex_Newline = /(?=\r?\n|\r)/g;`
//
// non-greedy y*?
// non-greedy y+?
// Named Capture Group(?<Name>y)
// #####################################################################
// const regex = /```ad-(\w+)\r?\ntitle:(.+?)\((\d*?)\)\r?\n(.+?)```/
const regex =
/```ad-(\w+)\r?\ntitle:\s*(?<Title>.+?)\s*\((?<Points>\d*?)\)\r?\narea:\s*(?<Area>.+?)\s*\r?\ncover:\s*(?<Cover>.+?)\s*\r?\n(?<Content>.+?)```/;
// M21. define aoh_rows : a JavaScript array
// #####################################################################
let aoh_rows = [];
// M23. update aoh_rows :
// transform a JavaScript array into a Dataview data array by using dv.array
// #####################################################################
aoh_rows = dv.array(aoh_rows);
// M31. gather the formatted data :
// #####################################################################
for (const page of pages) {
// M31.FR10 define file:
// #####################################################################
const file = app.vault.getAbstractFileByPath(page.file.path);
// M31.FR12 define contents: Read the file contents
// #####################################################################
const contents = await app.vault.read(file);
// M31.FR14 Extract the summary via regex :
// g modifier: global. All matches (don't return after first match)
// s modifier: single line. Dot matches newline characters
// #####################################################################
for (const callout of contents.match(new RegExp(regex, "sg")) || []) {
// M31.FR14.FR11 define match :
// s modifier: single line. Dot matches newline characters
// #####################################################################
const match = callout.match(new RegExp(regex, "s"));
// M31.FR14.FR13 push the key/value pairs into the array aoh_rows:
// #####################################################################
// aoh_rows.push([match[2], match[3],match[4],match[5], page.file.link]);
// aoh_rows["values"].push({
// Title: match[2],
// Points: match[3],
// Area: match[4],
// Content: match[5],
// Link: page.file.link,
// });
aoh_rows["values"].push({
Title: match.groups?.Title,
Points: match.groups?.Points,
Area: match.groups?.Area,
Cover: match.groups?.Cover,
Content: match.groups?.Content,
Name_Of_File: page.file.name,
Path_Of_File: page.file.path,
Link_Of_File: page.file.link,
});
}
}
// M39. dedbug output aoh_rows:
// #####################################################################
// dv.span("The following is the content of the `aoh_rows` from the DVJS20.<br>");
// aoh_rows.forEach((h_row) => {
// if (h_row.Name_Of_File === "dic_19680301") {
// dv.span(JSON.stringify(h_row, null, 2), "\n");
// }
// });
// The following is the content of the aoh_rows from the DVJS20.
// [
// {
// Title: "Explain Recursion",
// Points: "5",
// Area: "General",
// Cover: "![|150](file:///E:/Q27_test_data_images/Q27_General01.jpg)", //=>It is rendered as a image.
// Content: "For an explaition of recursion, please look up Recursion\n",
// Name_Of_File: "dic_19680301",
// Path_Of_File:
// "100_Project/01_dataviewjs/01_by_example/Q27_Admonition/Q27_test_data/03/dic_19680301.md",
// Link_Of_File: {
// path: "100_Project/01_dataviewjs/01_by_example/Q27_Admonition/Q27_test_data/03/dic_19680301.md",
// embed: false,
// type: "file",
// },
// },
// {
// Title: "Explain Mergesort",
// Points: "3",
// Area: "Sorting",
// Cover: "![|150](file:///E:/Q27_test_data_images/Q27_Sorting01.jpg)", //=>It is rendered as a image.
// Content: "It is 42\n",
// Name_Of_File: "dic_19680301",
// Path_Of_File:
// "100_Project/01_dataviewjs/01_by_example/Q27_Admonition/Q27_test_data/03/dic_19680301.md",
// Link_Of_File: {
// path: "100_Project/01_dataviewjs/01_by_example/Q27_Admonition/Q27_test_data/03/dic_19680301.md",
// embed: false,
// type: "file",
// },
// },
// {
// Title: "Explain Iteration",
// Points: "2",
// Area: "Loop",
// Cover: "![|150](file:///E:/Q27_test_data_images/Q27_Loop01.jpg)", //=>It is rendered as a image.
// Content: "It is the opposite of recursion\n",
// Name_Of_File: "dic_19680301",
// Path_Of_File:
// "100_Project/01_dataviewjs/01_by_example/Q27_Admonition/Q27_test_data/03/dic_19680301.md",
// Link_Of_File: {
// path: "100_Project/01_dataviewjs/01_by_example/Q27_Admonition/Q27_test_data/03/dic_19680301.md",
// embed: false,
// type: "file",
// },
// },
// ];
// M41. filter and sort aoh_rows:
// #####################################################################
// aoh_rows = aoh_rows
// .where((h_row) => h_row.Area)
// // .where((h_row) => dv.func.contains(h_row.Title, "Explain"))
// .where((h_row) =>
// /Iteration|Mergesort|Recursion/.test(h_row.Title)
// )
// .sort((h_row) => h_row.Title, "asc");
// M51. define groups:
// groupBy_CASE:To group each `h_row` of the `aoh_rows` by `h_row.Title` AS `G1`
// (G1=group.rows)(key=group.key)
// (comments)sort_CASE:To sort each `G1` of the `group.rows` by `group.key` in descending order
// #####################################################################
let groups = aoh_rows
.groupBy((h_row) => h_row.Title); // groupBy: (default) in ascending order
//.sort((group) => group.key, "desc");
// M61. Output aoh_rows as a table:
// #####################################################################
//dv.span(aoh_rows);
dv.table(
["Area", "Cover", "Question", "Points", "Content", "Exame"],
groups.map((group) => [
group.rows.Area[0],
group.rows.Cover[0],
group.rows.Title[0],
group.rows.Points,
group.rows.Content,
group.rows.Link_Of_File.join(", "),
])
);
```