Upgrade to 2.0.0, see changelog
This commit is contained in:
parent
527f58d679
commit
c75f252a9c
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "unofficial-jisho-api-dart",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"program": "example/api/phrase_search_copy.dart"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,3 +1,9 @@
|
||||||
|
## 2.0.0
|
||||||
|
|
||||||
|
- Upgrade library to use null-safety
|
||||||
|
- Wrap the result data in "Data" classes that are nullable if no result was found
|
||||||
|
- Add sound data to phrase scrape results
|
||||||
|
|
||||||
## 1.1.0
|
## 1.1.0
|
||||||
|
|
||||||
- Export object interfaces for both libraries
|
- Export object interfaces for both libraries
|
||||||
|
|
|
@ -8,8 +8,6 @@ include: package:effective_dart/analysis_options.yaml
|
||||||
# Uncomment to specify additional rules.
|
# Uncomment to specify additional rules.
|
||||||
linter:
|
linter:
|
||||||
rules:
|
rules:
|
||||||
public_member_api_docs: false
|
|
||||||
lines_longer_than_80_chars: false
|
lines_longer_than_80_chars: false
|
||||||
omit_local_variable_types: false
|
|
||||||
|
|
||||||
analyzer:
|
analyzer:
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import 'dart:convert' show jsonEncode;
|
import 'dart:convert' show jsonEncode;
|
||||||
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
||||||
|
|
||||||
void main() async {
|
void main() {
|
||||||
await jisho.searchForExamples('日').then((result) {
|
jisho.searchForExamples('日').then((result) {
|
||||||
print('Jisho Uri: ${result.uri}');
|
print('Jisho Uri: ${result.uri}');
|
||||||
print('');
|
print('');
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,27 @@
|
||||||
import 'dart:convert' show jsonEncode;
|
import 'dart:convert' show jsonEncode;
|
||||||
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
||||||
|
|
||||||
void main() async {
|
void main() {
|
||||||
await jisho.searchForKanji('語').then((result) {
|
jisho.searchForKanji('語').then((result) {
|
||||||
print('Found: ${result.found}');
|
print('Found: ${result.found}');
|
||||||
print('Taught in: ${result.taughtIn}');
|
|
||||||
print('JLPT level: ${result.jlptLevel}');
|
final data = result.data;
|
||||||
print('Newspaper frequency rank: ${result.newspaperFrequencyRank}');
|
if (data != null) {
|
||||||
print('Stroke count: ${result.strokeCount}');
|
print('Taught in: ${data.taughtIn}');
|
||||||
print('Meaning: ${result.meaning}');
|
print('JLPT level: ${data.jlptLevel}');
|
||||||
print('Kunyomi: ${jsonEncode(result.kunyomi)}');
|
print('Newspaper frequency rank: ${data.newspaperFrequencyRank}');
|
||||||
print('Kunyomi example: ${jsonEncode(result.kunyomiExamples[0])}');
|
print('Stroke count: ${data.strokeCount}');
|
||||||
print('Onyomi: ${jsonEncode(result.onyomi)}');
|
print('Meaning: ${data.meaning}');
|
||||||
print('Onyomi example: ${jsonEncode(result.onyomiExamples[0])}');
|
print('Kunyomi: ${jsonEncode(data.kunyomi)}');
|
||||||
print('Radical: ${jsonEncode(result.radical)}');
|
print('Kunyomi example: ${jsonEncode(data.kunyomiExamples[0])}');
|
||||||
print('Parts: ${jsonEncode(result.parts)}');
|
print('Onyomi: ${jsonEncode(data.onyomi)}');
|
||||||
print('Stroke order diagram: ${result.strokeOrderDiagramUri}');
|
print('Onyomi example: ${jsonEncode(data.onyomiExamples[0])}');
|
||||||
print('Stroke order SVG: ${result.strokeOrderSvgUri}');
|
print('Radical: ${jsonEncode(data.radical)}');
|
||||||
print('Stroke order GIF: ${result.strokeOrderGifUri}');
|
print('Parts: ${jsonEncode(data.parts)}');
|
||||||
print('Jisho Uri: ${result.uri}');
|
print('Stroke order diagram: ${data.strokeOrderDiagramUri}');
|
||||||
|
print('Stroke order SVG: ${data.strokeOrderSvgUri}');
|
||||||
|
print('Stroke order GIF: ${data.strokeOrderGifUri}');
|
||||||
|
print('Jisho Uri: ${data.uri}');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -2,8 +2,8 @@ import 'dart:convert';
|
||||||
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
||||||
final JsonEncoder encoder = JsonEncoder.withIndent(' ');
|
final JsonEncoder encoder = JsonEncoder.withIndent(' ');
|
||||||
|
|
||||||
void main() async {
|
void main() {
|
||||||
await jisho.scrapeForPhrase('谷').then((data) {
|
jisho.scrapeForPhrase('谷').then((data) {
|
||||||
print(encoder.convert(data));
|
print(encoder.convert(data));
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -2,8 +2,9 @@ import 'dart:convert';
|
||||||
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
import 'package:unofficial_jisho_api/api.dart' as jisho;
|
||||||
final JsonEncoder encoder = JsonEncoder.withIndent(' ');
|
final JsonEncoder encoder = JsonEncoder.withIndent(' ');
|
||||||
|
|
||||||
void main() async {
|
void main() {
|
||||||
await jisho.searchForPhrase('日').then((result) {
|
jisho.searchForPhrase('日').then((result) {
|
||||||
|
// jisho.searchForPhrase('する').then((result) {
|
||||||
print(encoder.convert(result));
|
print(encoder.convert(result));
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -5,11 +5,12 @@ import 'package:unofficial_jisho_api/parser.dart' as jisho_parser;
|
||||||
final JsonEncoder encoder = JsonEncoder.withIndent(' ');
|
final JsonEncoder encoder = JsonEncoder.withIndent(' ');
|
||||||
|
|
||||||
const String searchExample = '保護者';
|
const String searchExample = '保護者';
|
||||||
final String searchURI = jisho_parser.uriForExampleSearch(searchExample);
|
final Uri searchURI = jisho_parser.uriForExampleSearch(searchExample);
|
||||||
|
|
||||||
void main() async {
|
void main() {
|
||||||
await http.get(searchURI).then((result) {
|
http.get(searchURI).then((result) {
|
||||||
final parsedResult = jisho_parser.parseExamplePageData(result.body, searchExample);
|
final parsedResult =
|
||||||
|
jisho_parser.parseExamplePageData(result.body, searchExample);
|
||||||
print('English: ${parsedResult.results[0].english}');
|
print('English: ${parsedResult.results[0].english}');
|
||||||
print('Kanji ${parsedResult.results[0].kanji}');
|
print('Kanji ${parsedResult.results[0].kanji}');
|
||||||
print('Kana: ${parsedResult.results[0].kana}');
|
print('Kana: ${parsedResult.results[0].kana}');
|
||||||
|
|
|
@ -5,13 +5,17 @@ import 'package:unofficial_jisho_api/parser.dart' as jisho_parser;
|
||||||
final JsonEncoder encoder = JsonEncoder.withIndent(' ');
|
final JsonEncoder encoder = JsonEncoder.withIndent(' ');
|
||||||
|
|
||||||
const String searchKanji = '車';
|
const String searchKanji = '車';
|
||||||
final String searchURI = jisho_parser.uriForKanjiSearch(searchKanji);
|
final Uri searchURI = jisho_parser.uriForKanjiSearch(searchKanji);
|
||||||
|
|
||||||
void main() async {
|
void main() {
|
||||||
await http.get(searchURI).then((result) {
|
http.get(searchURI).then((result) {
|
||||||
final parsedResult = jisho_parser.parseKanjiPageData(result.body, searchKanji);
|
final parsedResult =
|
||||||
print('JLPT level: ${parsedResult.jlptLevel}');
|
jisho_parser.parseKanjiPageData(result.body, searchKanji);
|
||||||
print('Stroke count: ${parsedResult.strokeCount}');
|
final data = parsedResult.data;
|
||||||
print('Meaning: ${parsedResult.meaning}');
|
if (data != null) {
|
||||||
|
print('JLPT level: ${data.jlptLevel}');
|
||||||
|
print('Stroke count: ${data.strokeCount}');
|
||||||
|
print('Meaning: ${data.meaning}');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -5,12 +5,12 @@ import 'package:unofficial_jisho_api/parser.dart' as jisho_parser;
|
||||||
final JsonEncoder encoder = JsonEncoder.withIndent(' ');
|
final JsonEncoder encoder = JsonEncoder.withIndent(' ');
|
||||||
|
|
||||||
const String searchExample = '保護者';
|
const String searchExample = '保護者';
|
||||||
final String searchURI = jisho_parser.uriForPhraseScrape(searchExample);
|
final Uri searchURI = jisho_parser.uriForPhraseScrape(searchExample);
|
||||||
|
|
||||||
void main() async {
|
void main() {
|
||||||
|
http.get(searchURI).then((result) {
|
||||||
await http.get(searchURI).then((result) {
|
final parsedResult =
|
||||||
final parsedResult = jisho_parser.parsePhrasePageData(result.body, searchExample);
|
jisho_parser.parsePhrasePageData(result.body, searchExample);
|
||||||
print(encoder.convert(parsedResult));
|
print(encoder.convert(parsedResult));
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -7,11 +7,11 @@ library unofficial_jisho_api;
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
import './src/exampleSearch.dart';
|
import './src/example_search.dart';
|
||||||
import './src/kanjiSearch.dart';
|
import './src/kanji_search.dart';
|
||||||
import './src/objects.dart';
|
import './src/objects.dart';
|
||||||
import './src/phraseScrape.dart';
|
import './src/phrase_scrape.dart';
|
||||||
import './src/phraseSearch.dart';
|
import './src/phrase_search.dart';
|
||||||
|
|
||||||
export './src/objects.dart';
|
export './src/objects.dart';
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,8 @@
|
||||||
/// for providing HTML.
|
/// for providing HTML.
|
||||||
library unofficial_jisho_parser;
|
library unofficial_jisho_parser;
|
||||||
|
|
||||||
export './src/exampleSearch.dart'
|
|
||||||
show uriForExampleSearch, parseExamplePageData;
|
|
||||||
export './src/kanjiSearch.dart' show uriForKanjiSearch, parseKanjiPageData;
|
|
||||||
export './src/objects.dart';
|
export './src/objects.dart';
|
||||||
export './src/phraseScrape.dart' show uriForPhraseScrape, parsePhrasePageData;
|
export 'src/example_search.dart' show uriForExampleSearch, parseExamplePageData;
|
||||||
export './src/phraseSearch.dart';
|
export 'src/kanji_search.dart' show uriForKanjiSearch, parseKanjiPageData;
|
||||||
|
export 'src/phrase_scrape.dart' show uriForPhraseScrape, parsePhrasePageData;
|
||||||
|
export 'src/phrase_search.dart';
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
const String JISHO_API = 'https://jisho.org/api/v1/search/words';
|
// ignore_for_file: public_member_api_docs
|
||||||
const String SCRAPE_BASE_URI = 'https://jisho.org/search/';
|
|
||||||
const String STROKE_ORDER_DIAGRAM_BASE_URI =
|
const String jishoApi = 'https://jisho.org/api/v1/search/words';
|
||||||
|
const String scrapeBaseUri = 'https://jisho.org/search/';
|
||||||
|
const String strokeOrderDiagramBaseUri =
|
||||||
'https://classic.jisho.org/static/images/stroke_diagrams/';
|
'https://classic.jisho.org/static/images/stroke_diagrams/';
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
import 'package:html/parser.dart';
|
|
||||||
import 'package:html/dom.dart';
|
import 'package:html/dom.dart';
|
||||||
|
import 'package:html/parser.dart';
|
||||||
|
|
||||||
import './base_uri.dart';
|
import './base_uri.dart';
|
||||||
import './objects.dart';
|
import './objects.dart';
|
||||||
|
import './scraping.dart';
|
||||||
|
|
||||||
final RegExp _kanjiRegex = RegExp(r'[\u4e00-\u9faf\u3400-\u4dbf]');
|
final RegExp _kanjiRegex = RegExp(r'[\u4e00-\u9faf\u3400-\u4dbf]');
|
||||||
|
|
||||||
/// Provides the URI for an example search
|
/// Provides the URI for an example search
|
||||||
String uriForExampleSearch(String phrase) {
|
Uri uriForExampleSearch(String phrase) {
|
||||||
return '$SCRAPE_BASE_URI${Uri.encodeComponent(phrase)}%23sentences';
|
return Uri.parse('$scrapeBaseUri${Uri.encodeComponent(phrase)}%23sentences');
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Element> _getChildrenAndSymbols(Element ul) {
|
List<Element> _getChildrenAndSymbols(Element ul) {
|
||||||
|
@ -16,7 +17,7 @@ List<Element> _getChildrenAndSymbols(Element ul) {
|
||||||
final ulCharArray = ulText.split('');
|
final ulCharArray = ulText.split('');
|
||||||
final ulChildren = ul.children;
|
final ulChildren = ul.children;
|
||||||
var offsetPointer = 0;
|
var offsetPointer = 0;
|
||||||
List<Element> result = [];
|
final result = <Element>[];
|
||||||
|
|
||||||
for (var element in ulChildren) {
|
for (var element in ulChildren) {
|
||||||
if (element.text !=
|
if (element.text !=
|
||||||
|
@ -40,8 +41,13 @@ List<Element> _getChildrenAndSymbols(Element ul) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExampleResultData _getKanjiAndKana(Element div) {
|
/// Although return type is List<String>, it is to be interpreted as (String, String)
|
||||||
final ul = div.querySelector('ul');
|
List<String> _getKanjiAndKana(Element div) {
|
||||||
|
final ul = assertNotNull(
|
||||||
|
variable: div.querySelector('ul'),
|
||||||
|
errorMessage:
|
||||||
|
"Could not parse kanji/kana div. Is the provided document corrupt, or has Jisho been updated?",
|
||||||
|
);
|
||||||
final contents = _getChildrenAndSymbols(ul);
|
final contents = _getChildrenAndSymbols(ul);
|
||||||
|
|
||||||
var kanji = '';
|
var kanji = '';
|
||||||
|
@ -51,7 +57,11 @@ ExampleResultData _getKanjiAndKana(Element div) {
|
||||||
if (content.localName == 'li') {
|
if (content.localName == 'li') {
|
||||||
final li = content;
|
final li = content;
|
||||||
final furigana = li.querySelector('.furigana')?.text;
|
final furigana = li.querySelector('.furigana')?.text;
|
||||||
final unlifted = li.querySelector('.unlinked')?.text;
|
final unlifted = assertNotNull(
|
||||||
|
variable: li.querySelector('.unlinked')?.text,
|
||||||
|
errorMessage:
|
||||||
|
"Could not parse a piece of the example sentence. Is the provided document corrupt, or has Jisho been updated?",
|
||||||
|
);
|
||||||
|
|
||||||
if (furigana != null) {
|
if (furigana != null) {
|
||||||
kanji += unlifted;
|
kanji += unlifted;
|
||||||
|
@ -74,39 +84,49 @@ ExampleResultData _getKanjiAndKana(Element div) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final text = content.text.trim();
|
final text = content.text.trim();
|
||||||
if (text != null) {
|
|
||||||
kanji += text;
|
kanji += text;
|
||||||
kana += text;
|
kana += text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return ExampleResultData(
|
return [kanji, kana];
|
||||||
kanji: kanji,
|
|
||||||
kana: kana,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ExampleSentencePiece> getPieces(Element sentenceElement) {
|
List<ExampleSentencePiece> getPieces(Element sentenceElement) {
|
||||||
final pieceElements = sentenceElement.querySelectorAll('li.clearfix');
|
final pieceElements = sentenceElement.querySelectorAll('li.clearfix');
|
||||||
final List<ExampleSentencePiece> pieces = [];
|
|
||||||
for (var pieceIndex = 0; pieceIndex < pieceElements.length; pieceIndex += 1) {
|
|
||||||
final pieceElement = pieceElements[pieceIndex];
|
|
||||||
pieces.add(ExampleSentencePiece(
|
|
||||||
lifted: pieceElement.querySelector('.furigana')?.text,
|
|
||||||
unlifted: pieceElement.querySelector('.unlinked')?.text,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
return pieces;
|
return pieceElements.map((var e) {
|
||||||
|
final unlifted = assertNotNull(
|
||||||
|
variable: e.querySelector('.unlinked')?.text,
|
||||||
|
errorMessage:
|
||||||
|
"Could not parse a piece of the example sentence. Is the provided document corrupt, or has Jisho been updated?",
|
||||||
|
);
|
||||||
|
|
||||||
|
return ExampleSentencePiece(
|
||||||
|
lifted: e.querySelector('.furigana')?.text,
|
||||||
|
unlifted: unlifted,
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
ExampleResultData _parseExampleDiv(Element div) {
|
ExampleResultData _parseExampleDiv(Element div) {
|
||||||
final result = _getKanjiAndKana(div);
|
final result = _getKanjiAndKana(div);
|
||||||
result.english = div.querySelector('.english').text;
|
final kanji = result[0];
|
||||||
result.pieces = getPieces(div) ?? [];
|
final kana = result[1];
|
||||||
|
|
||||||
return result;
|
final english = assertNotNull(
|
||||||
|
variable: div.querySelector('.english')?.text,
|
||||||
|
errorMessage:
|
||||||
|
"Could not parse translation. Is the provided document corrupt, or has Jisho been updated?",
|
||||||
|
);
|
||||||
|
final pieces = getPieces(div);
|
||||||
|
|
||||||
|
return ExampleResultData(
|
||||||
|
english: english,
|
||||||
|
kanji: kanji,
|
||||||
|
kana: kana,
|
||||||
|
pieces: pieces,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a jisho example sentence search page to an object
|
/// Parses a jisho example sentence search page to an object
|
||||||
|
@ -119,7 +139,6 @@ ExampleResults parseExamplePageData(String pageHtml, String phrase) {
|
||||||
return ExampleResults(
|
return ExampleResults(
|
||||||
query: phrase,
|
query: phrase,
|
||||||
found: results.isNotEmpty,
|
found: results.isNotEmpty,
|
||||||
results: results ?? [],
|
results: results,
|
||||||
uri: uriForExampleSearch(phrase)
|
uri: uriForExampleSearch(phrase).toString());
|
||||||
);
|
|
||||||
}
|
}
|
|
@ -1,235 +0,0 @@
|
||||||
import 'package:html_unescape/html_unescape.dart' as html_entities;
|
|
||||||
|
|
||||||
import './base_uri.dart';
|
|
||||||
import './objects.dart';
|
|
||||||
|
|
||||||
final _htmlUnescape = html_entities.HtmlUnescape();
|
|
||||||
|
|
||||||
const _onyomiLocatorSymbol = 'On';
|
|
||||||
const _kunyomiLocatorSymbol = 'Kun';
|
|
||||||
|
|
||||||
String _removeNewlines(String str) {
|
|
||||||
return str.replaceAll(RegExp(r'(?:\r|\n)'), '').trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Provides the URI for a kanji search
|
|
||||||
String uriForKanjiSearch(String kanji) {
|
|
||||||
return '$SCRAPE_BASE_URI${Uri.encodeComponent(kanji)}%23kanji';
|
|
||||||
}
|
|
||||||
|
|
||||||
String _getUriForStrokeOrderDiagram(String kanji) {
|
|
||||||
return '$STROKE_ORDER_DIAGRAM_BASE_URI${kanji.codeUnitAt(0)}_frames.png';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _containsKanjiGlyph(String pageHtml, String kanji) {
|
|
||||||
final kanjiGlyphToken =
|
|
||||||
'<h1 class="character" data-area-name="print" lang="ja">$kanji</h1>';
|
|
||||||
return pageHtml.contains(kanjiGlyphToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
String _getStringBetweenIndicies(String data, int startIndex, int endIndex) {
|
|
||||||
final result = data.substring(startIndex, endIndex);
|
|
||||||
return _removeNewlines(result).trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
String _getStringBetweenStrings(
|
|
||||||
String data, String startString, String endString) {
|
|
||||||
final regex = RegExp(
|
|
||||||
'${RegExp.escape(startString)}(.*?)${RegExp.escape(endString)}',
|
|
||||||
dotAll: true);
|
|
||||||
final match = regex.allMatches(data).toList();
|
|
||||||
|
|
||||||
return match.isNotEmpty ? match[0].group(1).toString() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _getIntBetweenStrings(
|
|
||||||
String pageHtml, String startString, String endString) {
|
|
||||||
final stringBetweenStrings =
|
|
||||||
_getStringBetweenStrings(pageHtml, startString, endString);
|
|
||||||
return int.parse(stringBetweenStrings);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> _getAllGlobalGroupMatches(String str, RegExp regex) {
|
|
||||||
var regexResults = regex.allMatches(str).toList();
|
|
||||||
List<String> results = [];
|
|
||||||
for (var match in regexResults) {
|
|
||||||
results.add(match.group(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> _parseAnchorsToArray(String str) {
|
|
||||||
final regex = RegExp(r'<a href=".*?">(.*?)<\/a>');
|
|
||||||
return _getAllGlobalGroupMatches(str, regex);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> _getYomi(String pageHtml, String yomiLocatorSymbol) {
|
|
||||||
final yomiSection = _getStringBetweenStrings(
|
|
||||||
pageHtml, '<dt>$yomiLocatorSymbol:</dt>', '</dl>');
|
|
||||||
return _parseAnchorsToArray(yomiSection ?? '');
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> _getKunyomi(String pageHtml) {
|
|
||||||
return _getYomi(pageHtml, _kunyomiLocatorSymbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> _getOnyomi(String pageHtml) {
|
|
||||||
return _getYomi(pageHtml, _onyomiLocatorSymbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<YomiExample> _getYomiExamples(String pageHtml, String yomiLocatorSymbol) {
|
|
||||||
final locatorString = '<h2>$yomiLocatorSymbol reading compounds</h2>';
|
|
||||||
final exampleSection =
|
|
||||||
_getStringBetweenStrings(pageHtml, locatorString, '</ul>');
|
|
||||||
if (exampleSection == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final regex = RegExp(r'<li>(.*?)<\/li>', dotAll: true);
|
|
||||||
final regexResults =
|
|
||||||
_getAllGlobalGroupMatches(exampleSection, regex).map((s) => s.trim());
|
|
||||||
|
|
||||||
final examples = regexResults.map((regexResult) {
|
|
||||||
final examplesLines = regexResult.split('\n').map((s) => s.trim()).toList();
|
|
||||||
return YomiExample(
|
|
||||||
example: examplesLines[0],
|
|
||||||
reading: examplesLines[1].replaceAll('【', '').replaceAll('】', ''),
|
|
||||||
meaning: _htmlUnescape.convert(examplesLines[2]),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return examples.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<YomiExample> _getOnyomiExamples(String pageHtml) {
|
|
||||||
return _getYomiExamples(pageHtml, _onyomiLocatorSymbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<YomiExample> _getKunyomiExamples(String pageHtml) {
|
|
||||||
return _getYomiExamples(pageHtml, _kunyomiLocatorSymbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
Radical _getRadical(String pageHtml) {
|
|
||||||
const radicalMeaningStartString = '<span class="radical_meaning">';
|
|
||||||
const radicalMeaningEndString = '</span>';
|
|
||||||
|
|
||||||
var radicalMeaning = _getStringBetweenStrings(
|
|
||||||
pageHtml,
|
|
||||||
radicalMeaningStartString,
|
|
||||||
radicalMeaningEndString,
|
|
||||||
).trim();
|
|
||||||
|
|
||||||
if (radicalMeaning != null) {
|
|
||||||
final radicalMeaningStartIndex =
|
|
||||||
pageHtml.indexOf(radicalMeaningStartString);
|
|
||||||
|
|
||||||
final radicalMeaningEndIndex = pageHtml.indexOf(
|
|
||||||
radicalMeaningEndString,
|
|
||||||
radicalMeaningStartIndex,
|
|
||||||
);
|
|
||||||
|
|
||||||
final radicalSymbolStartIndex =
|
|
||||||
radicalMeaningEndIndex + radicalMeaningEndString.length;
|
|
||||||
const radicalSymbolEndString = '</span>';
|
|
||||||
final radicalSymbolEndIndex =
|
|
||||||
pageHtml.indexOf(radicalSymbolEndString, radicalSymbolStartIndex);
|
|
||||||
|
|
||||||
final radicalSymbolsString = _getStringBetweenIndicies(
|
|
||||||
pageHtml,
|
|
||||||
radicalSymbolStartIndex,
|
|
||||||
radicalSymbolEndIndex,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (radicalSymbolsString.length > 1) {
|
|
||||||
final radicalForms = radicalSymbolsString
|
|
||||||
.substring(1)
|
|
||||||
.replaceAll('(', '')
|
|
||||||
.replaceAll(')', '')
|
|
||||||
.trim()
|
|
||||||
.split(', ');
|
|
||||||
|
|
||||||
return Radical(
|
|
||||||
symbol: radicalSymbolsString[0],
|
|
||||||
forms: radicalForms ?? [],
|
|
||||||
meaning: radicalMeaning);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Radical(symbol: radicalSymbolsString, meaning: radicalMeaning);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> _getParts(String pageHtml) {
|
|
||||||
const partsSectionStartString = '<dt>Parts:</dt>';
|
|
||||||
const partsSectionEndString = '</dl>';
|
|
||||||
|
|
||||||
final partsSection = _getStringBetweenStrings(
|
|
||||||
pageHtml,
|
|
||||||
partsSectionStartString,
|
|
||||||
partsSectionEndString,
|
|
||||||
);
|
|
||||||
|
|
||||||
var result = _parseAnchorsToArray(partsSection);
|
|
||||||
result.sort();
|
|
||||||
|
|
||||||
return (result);
|
|
||||||
}
|
|
||||||
|
|
||||||
String _getSvgUri(String pageHtml) {
|
|
||||||
var svgRegex = RegExp('\/\/.*?.cloudfront.net\/.*?.svg');
|
|
||||||
final regexResult = svgRegex.firstMatch(pageHtml).group(0).toString();
|
|
||||||
return regexResult.isNotEmpty ? 'https:$regexResult' : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
String _getGifUri(String kanji) {
|
|
||||||
final unicodeString = kanji.codeUnitAt(0).toRadixString(16);
|
|
||||||
final fileName = '$unicodeString.gif';
|
|
||||||
final animationUri =
|
|
||||||
'https://raw.githubusercontent.com/mistval/kanji_images/master/gifs/$fileName';
|
|
||||||
|
|
||||||
return animationUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _getNewspaperFrequencyRank(String pageHtml) {
|
|
||||||
final frequencySection =
|
|
||||||
_getStringBetweenStrings(pageHtml, '<div class="frequency">', '</div>');
|
|
||||||
return (frequencySection != null)
|
|
||||||
? int.parse(
|
|
||||||
_getStringBetweenStrings(frequencySection, '<strong>', '</strong>'))
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parses a jisho kanji search page to an object
|
|
||||||
KanjiResult parseKanjiPageData(String pageHtml, String kanji) {
|
|
||||||
final result = KanjiResult();
|
|
||||||
result.query = kanji;
|
|
||||||
result.found = _containsKanjiGlyph(pageHtml, kanji);
|
|
||||||
if (result.found == false) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.taughtIn =
|
|
||||||
_getStringBetweenStrings(pageHtml, 'taught in <strong>', '</strong>');
|
|
||||||
result.jlptLevel =
|
|
||||||
_getStringBetweenStrings(pageHtml, 'JLPT level <strong>', '</strong>');
|
|
||||||
result.newspaperFrequencyRank = _getNewspaperFrequencyRank(pageHtml);
|
|
||||||
result.strokeCount =
|
|
||||||
_getIntBetweenStrings(pageHtml, '<strong>', '</strong> strokes');
|
|
||||||
result.meaning = _htmlUnescape.convert(_removeNewlines(
|
|
||||||
_getStringBetweenStrings(
|
|
||||||
pageHtml, '<div class="kanji-details__main-meanings">', '</div>'))
|
|
||||||
.trim());
|
|
||||||
result.kunyomi = _getKunyomi(pageHtml) ?? [];
|
|
||||||
result.onyomi = _getOnyomi(pageHtml) ?? [];
|
|
||||||
result.onyomiExamples = _getOnyomiExamples(pageHtml) ?? [];
|
|
||||||
result.kunyomiExamples = _getKunyomiExamples(pageHtml) ?? [];
|
|
||||||
result.radical = _getRadical(pageHtml);
|
|
||||||
result.parts = _getParts(pageHtml) ?? [];
|
|
||||||
result.strokeOrderDiagramUri = _getUriForStrokeOrderDiagram(kanji);
|
|
||||||
result.strokeOrderSvgUri = _getSvgUri(pageHtml);
|
|
||||||
result.strokeOrderGifUri = _getGifUri(kanji);
|
|
||||||
result.uri = uriForKanjiSearch(kanji);
|
|
||||||
return result;
|
|
||||||
}
|
|
|
@ -0,0 +1,243 @@
|
||||||
|
import 'package:html_unescape/html_unescape.dart' as html_entities;
|
||||||
|
|
||||||
|
import './base_uri.dart';
|
||||||
|
import './objects.dart';
|
||||||
|
import './scraping.dart';
|
||||||
|
|
||||||
|
final _htmlUnescape = html_entities.HtmlUnescape();
|
||||||
|
|
||||||
|
const _onyomiLocatorSymbol = 'On';
|
||||||
|
const _kunyomiLocatorSymbol = 'Kun';
|
||||||
|
|
||||||
|
/// Provides the URI for a kanji search
|
||||||
|
Uri uriForKanjiSearch(String kanji) {
|
||||||
|
return Uri.parse('$scrapeBaseUri${Uri.encodeComponent(kanji)}%23kanji');
|
||||||
|
}
|
||||||
|
|
||||||
|
String _getUriForStrokeOrderDiagram(String kanji) {
|
||||||
|
return '$strokeOrderDiagramBaseUri${kanji.codeUnitAt(0)}_frames.png';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _containsKanjiGlyph(String pageHtml, String kanji) {
|
||||||
|
final kanjiGlyphToken =
|
||||||
|
'<h1 class="character" data-area-name="print" lang="ja">$kanji</h1>';
|
||||||
|
return pageHtml.contains(kanjiGlyphToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> _getYomi(String pageHtml, String yomiLocatorSymbol) {
|
||||||
|
final yomiSection = getStringBetweenStrings(
|
||||||
|
pageHtml, '<dt>$yomiLocatorSymbol:</dt>', '</dl>');
|
||||||
|
return parseAnchorsToArray(yomiSection ?? '');
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> _getKunyomi(String pageHtml) {
|
||||||
|
return _getYomi(pageHtml, _kunyomiLocatorSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> _getOnyomi(String pageHtml) {
|
||||||
|
return _getYomi(pageHtml, _onyomiLocatorSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<YomiExample> _getYomiExamples(String pageHtml, String yomiLocatorSymbol) {
|
||||||
|
final locatorString = '<h2>$yomiLocatorSymbol reading compounds</h2>';
|
||||||
|
final exampleSection =
|
||||||
|
getStringBetweenStrings(pageHtml, locatorString, '</ul>');
|
||||||
|
if (exampleSection == null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
final regex = RegExp(r'<li>(.*?)<\/li>', dotAll: true);
|
||||||
|
final regexResults =
|
||||||
|
getAllGlobalGroupMatches(exampleSection, regex).map((s) => s.trim());
|
||||||
|
|
||||||
|
final examples = regexResults.map((regexResult) {
|
||||||
|
final examplesLines = regexResult.split('\n').map((s) => s.trim()).toList();
|
||||||
|
return YomiExample(
|
||||||
|
example: examplesLines[0],
|
||||||
|
reading: examplesLines[1].replaceAll('【', '').replaceAll('】', ''),
|
||||||
|
meaning: _htmlUnescape.convert(examplesLines[2]),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return examples.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<YomiExample> _getOnyomiExamples(String pageHtml) {
|
||||||
|
return _getYomiExamples(pageHtml, _onyomiLocatorSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<YomiExample> _getKunyomiExamples(String pageHtml) {
|
||||||
|
return _getYomiExamples(pageHtml, _kunyomiLocatorSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
Radical? _getRadical(String pageHtml) {
|
||||||
|
const radicalMeaningStartString = '<span class="radical_meaning">';
|
||||||
|
const radicalMeaningEndString = '</span>';
|
||||||
|
|
||||||
|
var radicalMeaning = getStringBetweenStrings(
|
||||||
|
pageHtml,
|
||||||
|
radicalMeaningStartString,
|
||||||
|
radicalMeaningEndString,
|
||||||
|
)?.trim();
|
||||||
|
|
||||||
|
if (radicalMeaning == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final radicalMeaningStartIndex = pageHtml.indexOf(radicalMeaningStartString);
|
||||||
|
|
||||||
|
final radicalMeaningEndIndex = pageHtml.indexOf(
|
||||||
|
radicalMeaningEndString,
|
||||||
|
radicalMeaningStartIndex,
|
||||||
|
);
|
||||||
|
|
||||||
|
final radicalSymbolStartIndex =
|
||||||
|
radicalMeaningEndIndex + radicalMeaningEndString.length;
|
||||||
|
const radicalSymbolEndString = '</span>';
|
||||||
|
final radicalSymbolEndIndex =
|
||||||
|
pageHtml.indexOf(radicalSymbolEndString, radicalSymbolStartIndex);
|
||||||
|
|
||||||
|
final radicalSymbolsString = getStringBetweenIndicies(
|
||||||
|
pageHtml,
|
||||||
|
radicalSymbolStartIndex,
|
||||||
|
radicalSymbolEndIndex,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (radicalSymbolsString.length > 1) {
|
||||||
|
final radicalForms = radicalSymbolsString
|
||||||
|
.substring(1)
|
||||||
|
.replaceAll('(', '')
|
||||||
|
.replaceAll(')', '')
|
||||||
|
.trim()
|
||||||
|
.split(', ');
|
||||||
|
|
||||||
|
return Radical(
|
||||||
|
symbol: radicalSymbolsString[0],
|
||||||
|
forms: radicalForms,
|
||||||
|
meaning: radicalMeaning,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Radical(symbol: radicalSymbolsString, meaning: radicalMeaning);
|
||||||
|
}
|
||||||
|
|
||||||
|
String _getMeaning(String pageHtml) {
|
||||||
|
final rawMeaning = assertNotNull(
|
||||||
|
variable: getStringBetweenStrings(
|
||||||
|
pageHtml,
|
||||||
|
'<div class="kanji-details__main-meanings">',
|
||||||
|
'</div>',
|
||||||
|
),
|
||||||
|
errorMessage:
|
||||||
|
"Could not parse meaning. Is the provided document corrupt, or has Jisho been updated?",
|
||||||
|
);
|
||||||
|
|
||||||
|
return _htmlUnescape.convert(removeNewlines(rawMeaning).trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> _getParts(String pageHtml) {
|
||||||
|
const partsSectionStartString = '<dt>Parts:</dt>';
|
||||||
|
const partsSectionEndString = '</dl>';
|
||||||
|
|
||||||
|
final partsSection = getStringBetweenStrings(
|
||||||
|
pageHtml,
|
||||||
|
partsSectionStartString,
|
||||||
|
partsSectionEndString,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (partsSection == null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = parseAnchorsToArray(partsSection);
|
||||||
|
result.sort();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String _getSvgUri(String pageHtml) {
|
||||||
|
var svgRegex = RegExp('\/\/.*?.cloudfront.net\/.*?.svg');
|
||||||
|
|
||||||
|
final regexResult = assertNotNull(
|
||||||
|
variable: svgRegex.firstMatch(pageHtml)?.group(0)?.toString(),
|
||||||
|
errorMessage:
|
||||||
|
"Could not find SVG URI. Is the provided document corrupt, or has Jisho been updated?",
|
||||||
|
);
|
||||||
|
|
||||||
|
return 'https:$regexResult';
|
||||||
|
}
|
||||||
|
|
||||||
|
String _getGifUri(String kanji) {
|
||||||
|
final unicodeString = kanji.codeUnitAt(0).toRadixString(16);
|
||||||
|
final fileName = '$unicodeString.gif';
|
||||||
|
final animationUri =
|
||||||
|
'https://raw.githubusercontent.com/mistval/kanji_images/master/gifs/$fileName';
|
||||||
|
|
||||||
|
return animationUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
int? _getNewspaperFrequencyRank(String pageHtml) {
|
||||||
|
final frequencySection = getStringBetweenStrings(
|
||||||
|
pageHtml,
|
||||||
|
'<div class="frequency">',
|
||||||
|
'</div>',
|
||||||
|
);
|
||||||
|
|
||||||
|
// ignore: avoid_returning_null
|
||||||
|
if (frequencySection == null) return null;
|
||||||
|
|
||||||
|
final frequencyRank =
|
||||||
|
getStringBetweenStrings(frequencySection, '<strong>', '</strong>');
|
||||||
|
|
||||||
|
return frequencyRank != null ? int.parse(frequencyRank) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _getStrokeCount(String pageHtml) {
|
||||||
|
final strokeCount = assertNotNull(
|
||||||
|
variable: getIntBetweenStrings(pageHtml, '<strong>', '</strong> strokes'),
|
||||||
|
errorMessage:
|
||||||
|
"Could not parse stroke count. Is the provided document corrupt, or has Jisho been updated?",
|
||||||
|
);
|
||||||
|
|
||||||
|
return strokeCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
String? _getTaughtIn(String pageHtml) {
|
||||||
|
return getStringBetweenStrings(pageHtml, 'taught in <strong>', '</strong>');
|
||||||
|
}
|
||||||
|
|
||||||
|
String? _getJlptLevel(String pageHtml) {
|
||||||
|
return getStringBetweenStrings(pageHtml, 'JLPT level <strong>', '</strong>');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses a jisho kanji search page to an object
|
||||||
|
KanjiResult parseKanjiPageData(String pageHtml, String kanji) {
|
||||||
|
final result = KanjiResult(
|
||||||
|
query: kanji,
|
||||||
|
found: _containsKanjiGlyph(pageHtml, kanji),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.found == false) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.data = KanjiResultData(
|
||||||
|
strokeCount: _getStrokeCount(pageHtml),
|
||||||
|
meaning: _getMeaning(pageHtml),
|
||||||
|
strokeOrderDiagramUri: _getUriForStrokeOrderDiagram(kanji),
|
||||||
|
strokeOrderSvgUri: _getSvgUri(pageHtml),
|
||||||
|
strokeOrderGifUri: _getGifUri(kanji),
|
||||||
|
uri: uriForKanjiSearch(kanji).toString(),
|
||||||
|
parts: _getParts(pageHtml),
|
||||||
|
taughtIn: _getTaughtIn(pageHtml),
|
||||||
|
jlptLevel: _getJlptLevel(pageHtml),
|
||||||
|
newspaperFrequencyRank: _getNewspaperFrequencyRank(pageHtml),
|
||||||
|
kunyomi: _getKunyomi(pageHtml),
|
||||||
|
onyomi: _getOnyomi(pageHtml),
|
||||||
|
kunyomiExamples: _getKunyomiExamples(pageHtml),
|
||||||
|
onyomiExamples: _getOnyomiExamples(pageHtml),
|
||||||
|
radical: _getRadical(pageHtml),
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
|
@ -2,96 +2,157 @@
|
||||||
/* searchForKanji related classes */
|
/* searchForKanji related classes */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/// An example of a word that contains the kanji in question.
|
||||||
class YomiExample {
|
class YomiExample {
|
||||||
/// The original text of the example.
|
/// The original text of the example.
|
||||||
String example;
|
String example;
|
||||||
|
|
||||||
/// The reading of the example.
|
/// The reading of the example.
|
||||||
String reading;
|
String reading;
|
||||||
|
|
||||||
/// The meaning of the example.
|
/// The meaning of the example.
|
||||||
String meaning;
|
String meaning;
|
||||||
|
|
||||||
YomiExample({this.example, this.reading, this.meaning});
|
// ignore: public_member_api_docs
|
||||||
|
YomiExample({
|
||||||
|
required this.example,
|
||||||
|
required this.reading,
|
||||||
|
required this.meaning,
|
||||||
|
});
|
||||||
|
|
||||||
Map<String, String> toJson() =>
|
// ignore: public_member_api_docs
|
||||||
{'example': example, 'reading': reading, 'meaning': meaning};
|
Map<String, String> toJson() => {
|
||||||
|
'example': example,
|
||||||
|
'reading': reading,
|
||||||
|
'meaning': meaning,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Information regarding the radical of a kanji.
|
||||||
class Radical {
|
class Radical {
|
||||||
/// The radical symbol, if applicable.
|
/// The radical symbol.
|
||||||
String symbol;
|
String symbol;
|
||||||
/// The radical forms used in this kanji, if applicable.
|
|
||||||
|
/// The radical forms used in this kanji.
|
||||||
List<String> forms;
|
List<String> forms;
|
||||||
/// The meaning of the radical, if applicable.
|
|
||||||
|
/// The meaning of the radical.
|
||||||
String meaning;
|
String meaning;
|
||||||
|
|
||||||
Radical({this.symbol, this.forms, this.meaning});
|
// ignore: public_member_api_docs
|
||||||
|
Radical({
|
||||||
|
required this.symbol,
|
||||||
|
this.forms = const [],
|
||||||
|
required this.meaning,
|
||||||
|
});
|
||||||
|
|
||||||
Map<String, dynamic> toJson() =>
|
// ignore: public_member_api_docs
|
||||||
{'symbol': symbol, 'forms': forms, 'meaning': meaning};
|
Map<String, dynamic> toJson() => {
|
||||||
|
'symbol': symbol,
|
||||||
|
'forms': forms,
|
||||||
|
'meaning': meaning,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The main wrapper containing data about the query and whether or not it was successful.
|
||||||
class KanjiResult {
|
class KanjiResult {
|
||||||
/// True if results were found.
|
/// True if results were found.
|
||||||
String query;
|
String query;
|
||||||
|
|
||||||
/// The term that you searched for.
|
/// The term that you searched for.
|
||||||
bool found;
|
bool found;
|
||||||
|
|
||||||
/// The school level that the kanji is taught in, if applicable.
|
/// The result data if search was successful.
|
||||||
String taughtIn;
|
KanjiResultData? data;
|
||||||
/// The lowest JLPT exam that this kanji is likely to appear in, if applicable.
|
|
||||||
///
|
|
||||||
/// 'N5' or 'N4' or 'N3' or 'N2' or 'N1'.
|
|
||||||
String jlptLevel;
|
|
||||||
/// A number representing this kanji's frequency rank in newspapers, if applicable.
|
|
||||||
int newspaperFrequencyRank;
|
|
||||||
/// How many strokes this kanji is typically drawn in, if applicable.
|
|
||||||
int strokeCount;
|
|
||||||
/// The meaning of the kanji, if applicable.
|
|
||||||
String meaning;
|
|
||||||
/// This character's kunyomi, if applicable.
|
|
||||||
List<String> kunyomi;
|
|
||||||
/// This character's onyomi, if applicable.
|
|
||||||
List<String> onyomi;
|
|
||||||
/// Examples of this character's kunyomi being used, if applicable.
|
|
||||||
List<YomiExample> kunyomiExamples;
|
|
||||||
/// Examples of this character's onyomi being used, if applicable.
|
|
||||||
List<YomiExample> onyomiExamples;
|
|
||||||
/// Information about this character's radical, if applicable.
|
|
||||||
Radical radical;
|
|
||||||
/// The parts used in this kanji, if applicable.
|
|
||||||
List<String> parts;
|
|
||||||
/// The URL to a diagram showing how to draw this kanji step by step, if applicable.
|
|
||||||
String strokeOrderDiagramUri;
|
|
||||||
/// The URL to an SVG describing how to draw this kanji, if applicable.
|
|
||||||
String strokeOrderSvgUri;
|
|
||||||
/// The URL to a gif showing the kanji being draw and its stroke order, if applicable.
|
|
||||||
String strokeOrderGifUri;
|
|
||||||
/// The URI that these results were scraped from, if applicable.
|
|
||||||
String uri;
|
|
||||||
|
|
||||||
KanjiResult(
|
// ignore: public_member_api_docs
|
||||||
{this.query,
|
KanjiResult({
|
||||||
this.found,
|
required this.query,
|
||||||
this.taughtIn,
|
required this.found,
|
||||||
this.jlptLevel,
|
this.data,
|
||||||
this.newspaperFrequencyRank,
|
});
|
||||||
this.strokeCount,
|
|
||||||
this.meaning,
|
|
||||||
this.kunyomi,
|
|
||||||
this.onyomi,
|
|
||||||
this.kunyomiExamples,
|
|
||||||
this.onyomiExamples,
|
|
||||||
this.radical,
|
|
||||||
this.parts,
|
|
||||||
this.strokeOrderDiagramUri,
|
|
||||||
this.strokeOrderSvgUri,
|
|
||||||
this.strokeOrderGifUri,
|
|
||||||
this.uri});
|
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {
|
||||||
'query': query,
|
'query': query,
|
||||||
'found': found,
|
'found': found,
|
||||||
|
'data': data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The main kanji data class, collecting all the result information in one place.
|
||||||
|
class KanjiResultData {
|
||||||
|
/// The school level that the kanji is taught in, if applicable.
|
||||||
|
String? taughtIn;
|
||||||
|
|
||||||
|
/// The lowest JLPT exam that this kanji is likely to appear in, if applicable.
|
||||||
|
///
|
||||||
|
/// 'N5' or 'N4' or 'N3' or 'N2' or 'N1'.
|
||||||
|
String? jlptLevel;
|
||||||
|
|
||||||
|
/// A number representing this kanji's frequency rank in newspapers, if applicable.
|
||||||
|
int? newspaperFrequencyRank;
|
||||||
|
|
||||||
|
/// How many strokes this kanji is typically drawn in.
|
||||||
|
int strokeCount;
|
||||||
|
|
||||||
|
/// The meaning of the kanji.
|
||||||
|
String meaning;
|
||||||
|
|
||||||
|
/// This character's kunyomi.
|
||||||
|
List<String> kunyomi;
|
||||||
|
|
||||||
|
/// This character's onyomi.
|
||||||
|
List<String> onyomi;
|
||||||
|
|
||||||
|
/// Examples of this character's kunyomi being used.
|
||||||
|
List<YomiExample> kunyomiExamples;
|
||||||
|
|
||||||
|
/// Examples of this character's onyomi being used.
|
||||||
|
List<YomiExample> onyomiExamples;
|
||||||
|
|
||||||
|
/// Information about this character's radical, if applicable.
|
||||||
|
Radical? radical;
|
||||||
|
|
||||||
|
/// The parts used in this kanji.
|
||||||
|
List<String> parts;
|
||||||
|
|
||||||
|
/// The URL to a diagram showing how to draw this kanji step by step.
|
||||||
|
String strokeOrderDiagramUri;
|
||||||
|
|
||||||
|
/// The URL to an SVG describing how to draw this kanji.
|
||||||
|
String strokeOrderSvgUri;
|
||||||
|
|
||||||
|
/// The URL to a gif showing the kanji being draw and its stroke order.
|
||||||
|
String strokeOrderGifUri;
|
||||||
|
|
||||||
|
/// The URI that these results were scraped from.
|
||||||
|
String uri;
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
KanjiResultData({
|
||||||
|
this.taughtIn,
|
||||||
|
this.jlptLevel,
|
||||||
|
this.newspaperFrequencyRank,
|
||||||
|
required this.strokeCount,
|
||||||
|
required this.meaning,
|
||||||
|
this.kunyomi = const [],
|
||||||
|
this.onyomi = const [],
|
||||||
|
this.kunyomiExamples = const [],
|
||||||
|
this.onyomiExamples = const [],
|
||||||
|
this.radical,
|
||||||
|
this.parts = const [],
|
||||||
|
required this.strokeOrderDiagramUri,
|
||||||
|
required this.strokeOrderSvgUri,
|
||||||
|
required this.strokeOrderGifUri,
|
||||||
|
required this.uri,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
'taughtIn': taughtIn,
|
'taughtIn': taughtIn,
|
||||||
'jlptLevel': jlptLevel,
|
'jlptLevel': jlptLevel,
|
||||||
'newspaperFrequencyRank': newspaperFrequencyRank,
|
'newspaperFrequencyRank': newspaperFrequencyRank,
|
||||||
|
@ -101,12 +162,12 @@ class KanjiResult {
|
||||||
'onyomi': onyomi,
|
'onyomi': onyomi,
|
||||||
'onyomiExamples': onyomiExamples,
|
'onyomiExamples': onyomiExamples,
|
||||||
'kunyomiExamples': kunyomiExamples,
|
'kunyomiExamples': kunyomiExamples,
|
||||||
'radical': (radical != null) ? radical.toJson() : null,
|
'radical': radical?.toJson(),
|
||||||
'parts': parts,
|
'parts': parts,
|
||||||
'strokeOrderDiagramUri': strokeOrderDiagramUri,
|
'strokeOrderDiagramUri': strokeOrderDiagramUri,
|
||||||
'strokeOrderSvgUri': strokeOrderSvgUri,
|
'strokeOrderSvgUri': strokeOrderSvgUri,
|
||||||
'strokeOrderGifUri': strokeOrderGifUri,
|
'strokeOrderGifUri': strokeOrderGifUri,
|
||||||
'uri': uri
|
'uri': uri,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,54 +176,90 @@ class KanjiResult {
|
||||||
/* searchForExamples related classes */
|
/* searchForExamples related classes */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/// A word in an example sentence, consisting of either just kana, or kanji with furigana.
|
||||||
class ExampleSentencePiece {
|
class ExampleSentencePiece {
|
||||||
/// Baseline text shown on Jisho.org (below the lifted text / furigana)
|
/// Furigana text shown on Jisho.org (above the unlifted text), if applicable.
|
||||||
String lifted;
|
String? lifted;
|
||||||
/// Furigana text shown on Jisho.org (above the unlifted text)
|
|
||||||
|
/// Baseline text shown on Jisho.org (below the lifted text / furigana).
|
||||||
String unlifted;
|
String unlifted;
|
||||||
|
|
||||||
ExampleSentencePiece({this.lifted, this.unlifted});
|
// ignore: public_member_api_docs
|
||||||
|
ExampleSentencePiece({
|
||||||
|
this.lifted,
|
||||||
|
required this.unlifted,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {'lifted': lifted, 'unlifted': unlifted};
|
return {
|
||||||
|
'lifted': lifted,
|
||||||
|
'unlifted': unlifted,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// All data making up one example sentence.
|
||||||
class ExampleResultData {
|
class ExampleResultData {
|
||||||
/// The example sentence including kanji.
|
/// The example sentence including kanji.
|
||||||
String kanji;
|
String kanji;
|
||||||
|
|
||||||
/// The example sentence without kanji (only kana). Sometimes this may include some Kanji, as furigana is not always available from Jisho.org.
|
/// The example sentence without kanji (only kana). Sometimes this may include some Kanji, as furigana is not always available from Jisho.org.
|
||||||
String kana;
|
String kana;
|
||||||
|
|
||||||
/// An English translation of the example.
|
/// An English translation of the example.
|
||||||
String english;
|
String english;
|
||||||
|
|
||||||
/// The lifted/unlifted pairs that make up the sentence. Lifted text is furigana, unlifted is the text below the furigana.
|
/// The lifted/unlifted pairs that make up the sentence. Lifted text is furigana, unlifted is the text below the furigana.
|
||||||
List<ExampleSentencePiece> pieces;
|
List<ExampleSentencePiece> pieces;
|
||||||
|
|
||||||
ExampleResultData({this.english, this.kanji, this.kana, this.pieces});
|
// ignore: public_member_api_docs
|
||||||
|
ExampleResultData({
|
||||||
|
required this.english,
|
||||||
|
required this.kanji,
|
||||||
|
required this.kana,
|
||||||
|
required this.pieces,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {'english': english, 'kanji': kanji, 'kana': kana, 'pieces': pieces};
|
return {
|
||||||
|
'english': english,
|
||||||
|
'kanji': kanji,
|
||||||
|
'kana': kana,
|
||||||
|
'pieces': pieces,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// The main wrapper containing data about the query and whether or not it was successful.
|
||||||
class ExampleResults {
|
class ExampleResults {
|
||||||
/// The term that you searched for.
|
/// The term that you searched for.
|
||||||
String query;
|
String query;
|
||||||
|
|
||||||
/// True if results were found.
|
/// True if results were found.
|
||||||
bool found;
|
bool found;
|
||||||
|
|
||||||
/// The URI that these results were scraped from.
|
/// The URI that these results were scraped from.
|
||||||
String uri;
|
String uri;
|
||||||
|
|
||||||
/// The examples that were found, if any.
|
/// The examples that were found, if any.
|
||||||
List<ExampleResultData> results;
|
List<ExampleResultData> results;
|
||||||
|
|
||||||
ExampleResults({this.query, this.found, this.results, this.uri});
|
// ignore: public_member_api_docs
|
||||||
|
ExampleResults({
|
||||||
|
required this.query,
|
||||||
|
required this.found,
|
||||||
|
required this.results,
|
||||||
|
required this.uri,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {
|
||||||
'query': query,
|
'query': query,
|
||||||
'found': found,
|
'found': found,
|
||||||
'results': results,
|
'results': results,
|
||||||
'uri': uri
|
'uri': uri,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,96 +268,178 @@ class ExampleResults {
|
||||||
/* scrapeForPhrase related classes */
|
/* scrapeForPhrase related classes */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/// An example sentence.
|
||||||
class PhraseScrapeSentence {
|
class PhraseScrapeSentence {
|
||||||
/// The English meaning of the sentence.
|
/// The English meaning of the sentence.
|
||||||
String english;
|
String english;
|
||||||
|
|
||||||
/// The Japanese text of the sentence.
|
/// The Japanese text of the sentence.
|
||||||
String japanese;
|
String japanese;
|
||||||
|
|
||||||
/// The lifted/unlifted pairs that make up the sentence. Lifted text is furigana, unlifted is the text below the furigana.
|
/// The lifted/unlifted pairs that make up the sentence. Lifted text is furigana, unlifted is the text below the furigana.
|
||||||
List<ExampleSentencePiece> pieces;
|
List<ExampleSentencePiece> pieces;
|
||||||
|
|
||||||
PhraseScrapeSentence({this.english, this.japanese, this.pieces});
|
// ignore: public_member_api_docs
|
||||||
|
PhraseScrapeSentence({
|
||||||
|
required this.english,
|
||||||
|
required this.japanese,
|
||||||
|
required this.pieces,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
Map<String, dynamic> toJson() =>
|
Map<String, dynamic> toJson() =>
|
||||||
{'english': english, 'japanese': japanese, 'pieces': pieces};
|
{'english': english, 'japanese': japanese, 'pieces': pieces};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The data representing one "meaning" or "sense" of the word
|
||||||
class PhraseScrapeMeaning {
|
class PhraseScrapeMeaning {
|
||||||
/// The words that Jisho lists as "see also".
|
/// The words that Jisho lists as "see also".
|
||||||
List<String> seeAlsoTerms;
|
List<String> seeAlsoTerms;
|
||||||
|
|
||||||
/// Example sentences for this meaning.
|
/// Example sentences for this meaning.
|
||||||
List<PhraseScrapeSentence> sentences;
|
List<PhraseScrapeSentence> sentences;
|
||||||
/// The definition of the meaning
|
|
||||||
|
/// The definition of the meaning.
|
||||||
String definition;
|
String definition;
|
||||||
|
|
||||||
/// Supplemental information.
|
/// Supplemental information.
|
||||||
/// For example "usually written using kana alone".
|
/// For example "usually written using kana alone".
|
||||||
List<String> supplemental;
|
List<String> supplemental;
|
||||||
|
|
||||||
/// An "abstract" definition.
|
/// An "abstract" definition.
|
||||||
/// Often this is a Wikipedia definition.
|
/// Often this is a Wikipedia definition.
|
||||||
String definitionAbstract;
|
String? definitionAbstract;
|
||||||
|
|
||||||
/// Tags associated with this meaning.
|
/// Tags associated with this meaning.
|
||||||
List<String> tags;
|
List<String> tags;
|
||||||
|
|
||||||
PhraseScrapeMeaning(
|
// ignore: public_member_api_docs
|
||||||
{this.seeAlsoTerms,
|
PhraseScrapeMeaning({
|
||||||
this.sentences,
|
this.seeAlsoTerms = const [],
|
||||||
this.definition,
|
required this.sentences,
|
||||||
this.supplemental,
|
required this.definition,
|
||||||
|
this.supplemental = const [],
|
||||||
this.definitionAbstract,
|
this.definitionAbstract,
|
||||||
this.tags});
|
this.tags = const [],
|
||||||
|
});
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
'seeAlsoTerms': seeAlsoTerms,
|
'seeAlsoTerms': seeAlsoTerms,
|
||||||
'sentences': sentences,
|
'sentences': sentences,
|
||||||
'definition': definition,
|
'definition': definition,
|
||||||
'supplemental': supplemental,
|
'supplemental': supplemental,
|
||||||
'definitionAbstract': definitionAbstract,
|
'definitionAbstract': definitionAbstract,
|
||||||
'tags': tags
|
'tags': tags,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A pair of kanji and potential furigana.
|
||||||
class KanjiKanaPair {
|
class KanjiKanaPair {
|
||||||
|
/// Kanji
|
||||||
String kanji;
|
String kanji;
|
||||||
String kana;
|
|
||||||
|
|
||||||
KanjiKanaPair({this.kanji, this.kana});
|
/// Furigana, if applicable.
|
||||||
|
String? kana;
|
||||||
|
|
||||||
Map<String, String> toJson() => {'kanji': kanji, 'kana': kana};
|
// ignore: public_member_api_docs
|
||||||
|
KanjiKanaPair({
|
||||||
|
required this.kanji,
|
||||||
|
this.kana,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'kanji': kanji,
|
||||||
|
'kana': kana,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The main wrapper containing data about the query and whether or not it was successful.
|
||||||
class PhrasePageScrapeResult {
|
class PhrasePageScrapeResult {
|
||||||
/// True if a result was found.
|
/// True if a result was found.
|
||||||
bool found;
|
bool found;
|
||||||
|
|
||||||
/// The term that you searched for.
|
/// The term that you searched for.
|
||||||
String query;
|
String query;
|
||||||
/// The URI that these results were scraped from, if a result was found.
|
|
||||||
String uri;
|
|
||||||
/// Other forms of the search term, if a result was found.
|
|
||||||
List<String> tags;
|
|
||||||
/// Information about the meanings associated with this search result.
|
|
||||||
List<PhraseScrapeMeaning> meanings;
|
|
||||||
/// Tags associated with this search result.
|
|
||||||
List<KanjiKanaPair> otherForms;
|
|
||||||
/// Notes associated with the search result.
|
|
||||||
List<String> notes;
|
|
||||||
|
|
||||||
PhrasePageScrapeResult(
|
/// The result data if search was successful.
|
||||||
{this.found,
|
PhrasePageScrapeResultData? data;
|
||||||
this.query,
|
|
||||||
this.uri,
|
|
||||||
this.tags,
|
|
||||||
this.meanings,
|
|
||||||
this.otherForms,
|
|
||||||
this.notes});
|
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
PhrasePageScrapeResult({
|
||||||
|
required this.found,
|
||||||
|
required this.query,
|
||||||
|
this.data,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
'found': found,
|
'found': found,
|
||||||
'query': query,
|
'query': query,
|
||||||
|
'data': data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pronounciation audio.
|
||||||
|
class AudioFile {
|
||||||
|
/// The uri of the audio file.
|
||||||
|
String uri;
|
||||||
|
|
||||||
|
/// The mimetype of the audio.
|
||||||
|
String mimetype;
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
AudioFile({
|
||||||
|
required this.uri,
|
||||||
|
required this.mimetype,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'uri': uri,
|
||||||
|
'mimetype': mimetype,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The main scrape data class, collecting all the result information in one place.
|
||||||
|
class PhrasePageScrapeResultData {
|
||||||
|
/// The URI that these results were scraped from.
|
||||||
|
String uri;
|
||||||
|
|
||||||
|
/// Other forms of the search term.
|
||||||
|
List<String> tags;
|
||||||
|
|
||||||
|
/// Information about the meanings associated with this search result.
|
||||||
|
List<PhraseScrapeMeaning> meanings;
|
||||||
|
|
||||||
|
/// Tags associated with this search result.
|
||||||
|
List<KanjiKanaPair> otherForms;
|
||||||
|
|
||||||
|
/// Pronounciation of the search result.
|
||||||
|
List<AudioFile> audio;
|
||||||
|
|
||||||
|
/// Notes associated with the search result.
|
||||||
|
List<String> notes;
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
PhrasePageScrapeResultData({
|
||||||
|
required this.uri,
|
||||||
|
this.tags = const [],
|
||||||
|
this.meanings = const [],
|
||||||
|
this.otherForms = const [],
|
||||||
|
this.audio = const [],
|
||||||
|
this.notes = const [],
|
||||||
|
});
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
'uri': uri,
|
'uri': uri,
|
||||||
'tags': tags,
|
'tags': tags,
|
||||||
'meanings': meanings,
|
'meanings': meanings,
|
||||||
'otherForms': otherForms,
|
'otherForms': otherForms,
|
||||||
'notes': notes
|
'audio': audio,
|
||||||
|
'notes': notes,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,85 +447,157 @@ class PhrasePageScrapeResult {
|
||||||
/* searchForPhrase related classes */
|
/* searchForPhrase related classes */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/// Kanji/Furigana pair, or just kana as word.
|
||||||
|
///
|
||||||
|
/// Which field acts as kanji and/or kana might be unreliable, which is why both are nullable.
|
||||||
class JishoJapaneseWord {
|
class JishoJapaneseWord {
|
||||||
String word;
|
/// Usually kanji or kana.
|
||||||
String reading;
|
String? word;
|
||||||
|
|
||||||
JishoJapaneseWord({this.word, this.reading});
|
/// Usually furigana, if applicable.
|
||||||
|
String? reading;
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
JishoJapaneseWord({
|
||||||
|
this.word,
|
||||||
|
this.reading,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
factory JishoJapaneseWord.fromJson(Map<String, dynamic> json) {
|
factory JishoJapaneseWord.fromJson(Map<String, dynamic> json) {
|
||||||
return JishoJapaneseWord(
|
return JishoJapaneseWord(
|
||||||
word: json['word'] as String, reading: json['reading'] as String);
|
word: json['word'] as String?,
|
||||||
|
reading: json['reading'] as String?,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {'word': word, 'reading': reading};
|
// ignore: public_member_api_docs
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'word': word,
|
||||||
|
'reading': reading,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Relevant links of the search result.
|
||||||
class JishoSenseLink {
|
class JishoSenseLink {
|
||||||
|
/// Description of the linked webpage.
|
||||||
String text;
|
String text;
|
||||||
|
|
||||||
|
/// Link to the webpage.
|
||||||
String url;
|
String url;
|
||||||
|
|
||||||
JishoSenseLink({this.text, this.url});
|
// ignore: public_member_api_docs
|
||||||
|
JishoSenseLink({required this.text, required this.url});
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
factory JishoSenseLink.fromJson(Map<String, dynamic> json) {
|
factory JishoSenseLink.fromJson(Map<String, dynamic> json) {
|
||||||
return JishoSenseLink(
|
return JishoSenseLink(
|
||||||
text: json['text'] as String, url: json['url'] as String);
|
text: json['text'] as String,
|
||||||
|
url: json['url'] as String,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {'text': text, 'url': url};
|
// ignore: public_member_api_docs
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'text': text,
|
||||||
|
'url': url,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Origin of the word (from other languages).
|
||||||
|
class JishoWordSource {
|
||||||
|
/// Origin language.
|
||||||
|
String language;
|
||||||
|
|
||||||
|
/// Origin word, if present.
|
||||||
|
String? word;
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
JishoWordSource({
|
||||||
|
required this.language,
|
||||||
|
this.word,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'language:': language,
|
||||||
|
'word': word,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// One sense of the word.
|
||||||
class JishoWordSense {
|
class JishoWordSense {
|
||||||
List<String> english_definitions;
|
/// The meaning(s) of the word.
|
||||||
List<String> parts_of_speech;
|
List<String> englishDefinitions;
|
||||||
|
|
||||||
|
/// Type of word (Noun, Verb, etc.).
|
||||||
|
List<String> partsOfSpeech;
|
||||||
|
|
||||||
|
/// Relevant links.
|
||||||
List<JishoSenseLink> links;
|
List<JishoSenseLink> links;
|
||||||
|
|
||||||
|
/// Relevant tags.
|
||||||
List<String> tags;
|
List<String> tags;
|
||||||
List<String> see_also;
|
|
||||||
|
/// Relevant words (might include synonyms).
|
||||||
|
List<String> seeAlso;
|
||||||
|
|
||||||
|
/// Words with opposite meaning.
|
||||||
List<String> antonyms;
|
List<String> antonyms;
|
||||||
List<dynamic> source;
|
|
||||||
|
/// Origins of the word (from other languages).
|
||||||
|
List<JishoWordSource> source;
|
||||||
|
|
||||||
|
/// Additional info.
|
||||||
List<String> info;
|
List<String> info;
|
||||||
List<dynamic> restrictions;
|
|
||||||
|
|
||||||
JishoWordSense(
|
/// Restrictions as to which variants of the japanese words are usable for this sense.
|
||||||
{this.english_definitions,
|
List<String> restrictions;
|
||||||
this.parts_of_speech,
|
|
||||||
this.links,
|
|
||||||
this.tags,
|
|
||||||
this.see_also,
|
|
||||||
this.antonyms,
|
|
||||||
this.source,
|
|
||||||
this.info,
|
|
||||||
this.restrictions});
|
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
JishoWordSense({
|
||||||
|
required this.englishDefinitions,
|
||||||
|
required this.partsOfSpeech,
|
||||||
|
this.links = const [],
|
||||||
|
this.tags = const [],
|
||||||
|
this.seeAlso = const [],
|
||||||
|
this.antonyms = const [],
|
||||||
|
this.source = const [],
|
||||||
|
this.info = const [],
|
||||||
|
this.restrictions = const [],
|
||||||
|
});
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
factory JishoWordSense.fromJson(Map<String, dynamic> json) {
|
factory JishoWordSense.fromJson(Map<String, dynamic> json) {
|
||||||
return JishoWordSense(
|
return JishoWordSense(
|
||||||
english_definitions: (json['english_definitions'] as List)
|
englishDefinitions: (json['english_definitions'] as List)
|
||||||
.map((result) => result as String)
|
.map((result) => result as String)
|
||||||
.toList(),
|
.toList(),
|
||||||
parts_of_speech: (json['parts_of_speech'] as List)
|
partsOfSpeech: (json['parts_of_speech'] as List)
|
||||||
.map((result) => result as String)
|
.map((result) => result as String)
|
||||||
.toList(),
|
.toList(),
|
||||||
links: (json['links'] as List)
|
links: (json['links'] as List)
|
||||||
.map((result) => JishoSenseLink.fromJson(result))
|
.map((result) => JishoSenseLink.fromJson(result))
|
||||||
.toList(),
|
.toList(),
|
||||||
tags: (json['tags'] as List).map((result) => result as String).toList(),
|
tags: (json['tags'] as List).map((result) => result as String).toList(),
|
||||||
see_also: (json['see_also'] as List)
|
seeAlso: (json['see_also'] as List)
|
||||||
.map((result) => result as String)
|
.map((result) => result as String)
|
||||||
.toList(),
|
.toList(),
|
||||||
antonyms: (json['antonyms'] as List)
|
antonyms: (json['antonyms'] as List)
|
||||||
.map((result) => result as String)
|
.map((result) => result as String)
|
||||||
.toList(),
|
.toList(),
|
||||||
source: json['source'] as List<dynamic>,
|
source: json['source'] as List<JishoWordSource>,
|
||||||
info: (json['info'] as List).map((result) => result as String).toList(),
|
info: (json['info'] as List).map((result) => result as String).toList(),
|
||||||
restrictions: json['restrictions'] as List<dynamic>);
|
restrictions: json['restrictions'] as List<String>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
'english_definitions': english_definitions,
|
'english_definitions': englishDefinitions,
|
||||||
'parts_of_speech': parts_of_speech,
|
'parts_of_speech': partsOfSpeech,
|
||||||
'links': links,
|
'links': links,
|
||||||
'tags': tags,
|
'tags': tags,
|
||||||
'see_also': see_also,
|
'see_also': seeAlso,
|
||||||
'antonyms': antonyms,
|
'antonyms': antonyms,
|
||||||
'source': source,
|
'source': source,
|
||||||
'info': info,
|
'info': info,
|
||||||
|
@ -354,48 +605,87 @@ class JishoWordSense {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The original source(s) of the result.
|
||||||
class JishoAttribution {
|
class JishoAttribution {
|
||||||
|
/// Whether jmdict was a source.
|
||||||
bool jmdict;
|
bool jmdict;
|
||||||
|
|
||||||
|
/// Whether jmnedict was a source.
|
||||||
bool jmnedict;
|
bool jmnedict;
|
||||||
String dbpedia;
|
|
||||||
|
|
||||||
JishoAttribution({this.jmdict, this.jmnedict, this.dbpedia});
|
/// Additional sources, if applicable.
|
||||||
|
String? dbpedia;
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
JishoAttribution({
|
||||||
|
required this.jmdict,
|
||||||
|
required this.jmnedict,
|
||||||
|
this.dbpedia,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
factory JishoAttribution.fromJson(Map<String, dynamic> json) {
|
factory JishoAttribution.fromJson(Map<String, dynamic> json) {
|
||||||
return JishoAttribution(
|
return JishoAttribution(
|
||||||
jmdict: (json['jmdict'].toString() == 'true'),
|
jmdict: (json['jmdict'].toString() == 'true'),
|
||||||
jmnedict: (json['jmnedict'].toString() == 'true'),
|
jmnedict: (json['jmnedict'].toString() == 'true'),
|
||||||
dbpedia: (json['dbpedia'].toString() != 'false')
|
dbpedia: (json['dbpedia'].toString() != 'false')
|
||||||
? json['dbpedia'].toString()
|
? json['dbpedia'].toString()
|
||||||
: null);
|
: null,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() =>
|
// ignore: public_member_api_docs
|
||||||
{'jmdict': jmdict, 'jmnedict': jmnedict, 'dbpedia': dbpedia};
|
Map<String, dynamic> toJson() => {
|
||||||
|
'jmdict': jmdict,
|
||||||
|
'jmnedict': jmnedict,
|
||||||
|
'dbpedia': dbpedia,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The main API data class, collecting all information of one result in one place.
|
||||||
class JishoResult {
|
class JishoResult {
|
||||||
|
/// The main version of the word
|
||||||
|
///
|
||||||
|
/// This value might sometimes appear as some kind of hash or encoded version of the word.
|
||||||
|
/// Whenever it happens, the word usually originates taken from dbpedia
|
||||||
String slug;
|
String slug;
|
||||||
bool is_common;
|
|
||||||
|
/// Whether the word is common.
|
||||||
|
///
|
||||||
|
/// Dbpedia sometimes omit this value.
|
||||||
|
bool? isCommon;
|
||||||
|
|
||||||
|
/// Related tags.
|
||||||
List<String> tags;
|
List<String> tags;
|
||||||
|
|
||||||
|
/// Relevant jlpt levels.
|
||||||
List<String> jlpt;
|
List<String> jlpt;
|
||||||
|
|
||||||
|
/// Japanese versions of the word.
|
||||||
List<JishoJapaneseWord> japanese;
|
List<JishoJapaneseWord> japanese;
|
||||||
|
|
||||||
|
/// Translations of the word.
|
||||||
List<JishoWordSense> senses;
|
List<JishoWordSense> senses;
|
||||||
|
|
||||||
|
/// Sources.
|
||||||
JishoAttribution attribution;
|
JishoAttribution attribution;
|
||||||
|
|
||||||
JishoResult(
|
// ignore: public_member_api_docs
|
||||||
{this.slug,
|
JishoResult({
|
||||||
this.is_common,
|
required this.slug,
|
||||||
this.tags,
|
required this.isCommon,
|
||||||
this.jlpt,
|
this.tags = const [],
|
||||||
this.japanese,
|
this.jlpt = const [],
|
||||||
this.senses,
|
required this.japanese,
|
||||||
this.attribution});
|
required this.senses,
|
||||||
|
required this.attribution,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
factory JishoResult.fromJson(Map<String, dynamic> json) {
|
factory JishoResult.fromJson(Map<String, dynamic> json) {
|
||||||
return JishoResult(
|
return JishoResult(
|
||||||
slug: json['slug'] as String,
|
slug: json['slug'] as String,
|
||||||
is_common: json['is_common'] as bool,
|
isCommon: json['is_common'] as bool?,
|
||||||
tags: (json['tags'] as List).map((result) => result as String).toList(),
|
tags: (json['tags'] as List).map((result) => result as String).toList(),
|
||||||
jlpt: (json['jlpt'] as List).map((result) => result as String).toList(),
|
jlpt: (json['jlpt'] as List).map((result) => result as String).toList(),
|
||||||
japanese: (json['japanese'] as List)
|
japanese: (json['japanese'] as List)
|
||||||
|
@ -404,38 +694,54 @@ class JishoResult {
|
||||||
senses: (json['senses'] as List)
|
senses: (json['senses'] as List)
|
||||||
.map((result) => JishoWordSense.fromJson(result))
|
.map((result) => JishoWordSense.fromJson(result))
|
||||||
.toList(),
|
.toList(),
|
||||||
attribution: JishoAttribution.fromJson(json['attribution']));
|
attribution: JishoAttribution.fromJson(json['attribution']),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
'slug': slug,
|
'slug': slug,
|
||||||
'is_common': is_common,
|
'is_common': isCommon,
|
||||||
'tags': tags,
|
'tags': tags,
|
||||||
'jlpt': jlpt,
|
'jlpt': jlpt,
|
||||||
'japanese': japanese,
|
'japanese': japanese,
|
||||||
'senses': senses,
|
'senses': senses,
|
||||||
'attribution': attribution
|
'attribution': attribution,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Metadata with result status.
|
||||||
class JishoResultMeta {
|
class JishoResultMeta {
|
||||||
|
/// HTTP status code.
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
JishoResultMeta({this.status});
|
// ignore: public_member_api_docs
|
||||||
|
JishoResultMeta({required this.status});
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
factory JishoResultMeta.fromJson(Map<String, dynamic> json) {
|
factory JishoResultMeta.fromJson(Map<String, dynamic> json) {
|
||||||
return JishoResultMeta(status: json['status'] as int);
|
return JishoResultMeta(status: json['status'] as int);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
Map<String, dynamic> toJson() => {'status': status};
|
Map<String, dynamic> toJson() => {'status': status};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The main API result wrapper containing whether it was successful, and potential results.
|
||||||
class JishoAPIResult {
|
class JishoAPIResult {
|
||||||
|
/// Metadata with result status.
|
||||||
JishoResultMeta meta;
|
JishoResultMeta meta;
|
||||||
List<JishoResult> data;
|
|
||||||
|
|
||||||
JishoAPIResult({this.meta, this.data});
|
/// Results.
|
||||||
|
List<JishoResult>? data;
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
JishoAPIResult({
|
||||||
|
required this.meta,
|
||||||
|
this.data,
|
||||||
|
});
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
factory JishoAPIResult.fromJson(Map<String, dynamic> json) {
|
factory JishoAPIResult.fromJson(Map<String, dynamic> json) {
|
||||||
return JishoAPIResult(
|
return JishoAPIResult(
|
||||||
meta: JishoResultMeta.fromJson(json['meta']),
|
meta: JishoResultMeta.fromJson(json['meta']),
|
||||||
|
@ -444,5 +750,6 @@ class JishoAPIResult {
|
||||||
.toList());
|
.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
Map<String, dynamic> toJson() => {'meta': meta.toJson(), 'data': data};
|
Map<String, dynamic> toJson() => {'meta': meta.toJson(), 'data': data};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,157 +0,0 @@
|
||||||
import 'package:html/parser.dart';
|
|
||||||
import 'package:html/dom.dart';
|
|
||||||
|
|
||||||
import './exampleSearch.dart' show getPieces;
|
|
||||||
import './objects.dart';
|
|
||||||
|
|
||||||
List<String> _getTags(Document document) {
|
|
||||||
final List<String> tags = [];
|
|
||||||
final tagElements = document.querySelectorAll('.concept_light-tag');
|
|
||||||
|
|
||||||
for (var i = 0; i < tagElements.length; i += 1) {
|
|
||||||
final tagText = tagElements[i].text;
|
|
||||||
tags.add(tagText);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tags;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> _getMostRecentWordTypes(Element child) {
|
|
||||||
return child.text.split(',').map((s) => s.trim().toLowerCase()).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<KanjiKanaPair> _getOtherForms(Element child) {
|
|
||||||
return child.text
|
|
||||||
.split('、')
|
|
||||||
.map((s) => s.replaceAll('【', '').replaceAll('】', '').split(' '))
|
|
||||||
.map((a) =>
|
|
||||||
(KanjiKanaPair(kanji: a[0], kana: (a.length == 2) ? a[1] : null)))
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> _getNotes(Element child) => child.text.split('\n');
|
|
||||||
|
|
||||||
String _getMeaning(Element child) =>
|
|
||||||
child.querySelector('.meaning-meaning').text;
|
|
||||||
|
|
||||||
String _getMeaningAbstract(Element child) {
|
|
||||||
final meaningAbstract = child.querySelector('.meaning-abstract');
|
|
||||||
if (meaningAbstract == null) return null;
|
|
||||||
|
|
||||||
for (var element in meaningAbstract.querySelectorAll('a')) {
|
|
||||||
element.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
return child.querySelector('.meaning-abstract')?.text;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> _getSupplemental(Element child) {
|
|
||||||
final supplemental = child.querySelector('.supplemental_info');
|
|
||||||
if (supplemental == null) return [];
|
|
||||||
return supplemental.text.split(',').map((s) => s.trim()).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> _getSeeAlsoTerms(List<String> supplemental) {
|
|
||||||
if (supplemental == null) return [];
|
|
||||||
|
|
||||||
final List<String> seeAlsoTerms = [];
|
|
||||||
for (var i = supplemental.length - 1; i >= 0; i -= 1) {
|
|
||||||
final supplementalEntry = supplemental[i];
|
|
||||||
if (supplementalEntry.startsWith('See also')) {
|
|
||||||
seeAlsoTerms.add(supplementalEntry.replaceAll('See also ', ''));
|
|
||||||
supplemental.removeAt(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return seeAlsoTerms;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<PhraseScrapeSentence> _getSentences(Element child) {
|
|
||||||
final sentenceElements =
|
|
||||||
child.querySelector('.sentences')?.querySelectorAll('.sentence');
|
|
||||||
if (sentenceElements == null) return [];
|
|
||||||
|
|
||||||
final List<PhraseScrapeSentence> sentences = [];
|
|
||||||
for (var sentenceIndex = 0;
|
|
||||||
sentenceIndex < (sentenceElements?.length ?? 0);
|
|
||||||
sentenceIndex += 1) {
|
|
||||||
final sentenceElement = sentenceElements[sentenceIndex];
|
|
||||||
|
|
||||||
final english = sentenceElement.querySelector('.english').text;
|
|
||||||
final pieces = getPieces(sentenceElement);
|
|
||||||
|
|
||||||
sentenceElement.querySelector('.english').remove();
|
|
||||||
for (var element in sentenceElement.children[0].children) {
|
|
||||||
element.querySelector('.furigana')?.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
final japanese = sentenceElement.text;
|
|
||||||
|
|
||||||
sentences.add(PhraseScrapeSentence(
|
|
||||||
english: english, japanese: japanese, pieces: pieces ?? []));
|
|
||||||
}
|
|
||||||
|
|
||||||
return sentences;
|
|
||||||
}
|
|
||||||
|
|
||||||
PhrasePageScrapeResult _getMeaningsOtherFormsAndNotes(Document document) {
|
|
||||||
final returnValues = PhrasePageScrapeResult(otherForms: [], notes: []);
|
|
||||||
|
|
||||||
final meaningsWrapper = document.querySelector('.meanings-wrapper');
|
|
||||||
if (meaningsWrapper == null) return PhrasePageScrapeResult(found: false);
|
|
||||||
returnValues.found = true;
|
|
||||||
|
|
||||||
final meaningsChildren = meaningsWrapper.children;
|
|
||||||
|
|
||||||
final List<PhraseScrapeMeaning> meanings = [];
|
|
||||||
var mostRecentWordTypes = [];
|
|
||||||
for (var meaningIndex = 0;
|
|
||||||
meaningIndex < meaningsChildren.length;
|
|
||||||
meaningIndex += 1) {
|
|
||||||
final child = meaningsChildren[meaningIndex];
|
|
||||||
|
|
||||||
if (child.className.contains('meaning-tags')) {
|
|
||||||
mostRecentWordTypes = _getMostRecentWordTypes(child);
|
|
||||||
} else if (mostRecentWordTypes[0] == 'other forms') {
|
|
||||||
returnValues.otherForms = _getOtherForms(child);
|
|
||||||
} else if (mostRecentWordTypes[0] == 'notes') {
|
|
||||||
returnValues.notes = _getNotes(child);
|
|
||||||
} else {
|
|
||||||
final meaning = _getMeaning(child);
|
|
||||||
final meaningAbstract = _getMeaningAbstract(child);
|
|
||||||
final supplemental = _getSupplemental(child);
|
|
||||||
final seeAlsoTerms = _getSeeAlsoTerms(supplemental);
|
|
||||||
final sentences = _getSentences(child);
|
|
||||||
|
|
||||||
meanings.add(PhraseScrapeMeaning(
|
|
||||||
seeAlsoTerms: seeAlsoTerms ?? [],
|
|
||||||
sentences: sentences ?? [],
|
|
||||||
definition: meaning,
|
|
||||||
supplemental: supplemental ?? [],
|
|
||||||
definitionAbstract: meaningAbstract,
|
|
||||||
tags: mostRecentWordTypes ?? [],
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
returnValues.meanings = meanings;
|
|
||||||
|
|
||||||
return returnValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Provides the URI for a phrase scrape
|
|
||||||
String uriForPhraseScrape(String searchTerm) {
|
|
||||||
return 'https://jisho.org/word/${Uri.encodeComponent(searchTerm)}';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parses a jisho word search page to an object
|
|
||||||
PhrasePageScrapeResult parsePhrasePageData(String pageHtml, String query) {
|
|
||||||
final document = parse(pageHtml);
|
|
||||||
final result = _getMeaningsOtherFormsAndNotes(document);
|
|
||||||
|
|
||||||
result.query = query;
|
|
||||||
if (!result.found) return result;
|
|
||||||
result.uri = uriForPhraseScrape(query);
|
|
||||||
result.tags = _getTags(document);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
import './base_uri.dart';
|
|
||||||
|
|
||||||
/// Provides the URI for a phrase search
|
|
||||||
String uriForPhraseSearch(String phrase) {
|
|
||||||
return '$JISHO_API?keyword=${Uri.encodeComponent(phrase)}';
|
|
||||||
}
|
|
|
@ -0,0 +1,202 @@
|
||||||
|
import 'package:html/dom.dart';
|
||||||
|
import 'package:html/parser.dart';
|
||||||
|
|
||||||
|
import './example_search.dart' show getPieces;
|
||||||
|
import './objects.dart';
|
||||||
|
import './scraping.dart';
|
||||||
|
|
||||||
|
List<String> _getTags(Document document) {
|
||||||
|
final tagElements = document.querySelectorAll('.concept_light-tag');
|
||||||
|
final tags = tagElements.map((tagElement) => tagElement.text).toList();
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> _getMostRecentWordTypes(Element child) {
|
||||||
|
return child.text.split(',').map((s) => s.trim().toLowerCase()).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<KanjiKanaPair> _getOtherForms(Element child) {
|
||||||
|
return child.text
|
||||||
|
.split('、')
|
||||||
|
.map((s) => s.replaceAll('【', '').replaceAll('】', '').split(' '))
|
||||||
|
.map((a) => (KanjiKanaPair(
|
||||||
|
kanji: a[0],
|
||||||
|
kana: (a.length == 2) ? a[1] : null,
|
||||||
|
)))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> _getNotes(Element child) => child.text.split('\n');
|
||||||
|
|
||||||
|
String _getMeaningString(Element child) {
|
||||||
|
final meaning = assertNotNull(
|
||||||
|
variable: child.querySelector('.meaning-meaning')?.text,
|
||||||
|
errorMessage:
|
||||||
|
"Could not parse meaning div. Is the provided document corrupt, or has Jisho been updated?",
|
||||||
|
);
|
||||||
|
|
||||||
|
return meaning;
|
||||||
|
}
|
||||||
|
|
||||||
|
String? _getMeaningAbstract(Element child) {
|
||||||
|
final meaningAbstract = child.querySelector('.meaning-abstract');
|
||||||
|
if (meaningAbstract == null) return null;
|
||||||
|
|
||||||
|
for (var element in meaningAbstract.querySelectorAll('a')) {
|
||||||
|
element.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
return child.querySelector('.meaning-abstract')?.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> _getSupplemental(Element child) {
|
||||||
|
final supplemental = child.querySelector('.supplemental_info');
|
||||||
|
if (supplemental == null) return [];
|
||||||
|
return supplemental.text.split(',').map((s) => s.trim()).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> _getSeeAlsoTerms(List<String> supplemental) {
|
||||||
|
// if (supplemental == null) return [];
|
||||||
|
|
||||||
|
final seeAlsoTerms = <String>[];
|
||||||
|
for (var i = supplemental.length - 1; i >= 0; i -= 1) {
|
||||||
|
final supplementalEntry = supplemental[i];
|
||||||
|
if (supplementalEntry.startsWith('See also')) {
|
||||||
|
seeAlsoTerms.add(supplementalEntry.replaceAll('See also ', ''));
|
||||||
|
supplemental.removeAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return seeAlsoTerms;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhraseScrapeSentence _getSentence(Element sentenceElement) {
|
||||||
|
final english = assertNotNull(
|
||||||
|
variable: sentenceElement.querySelector('.english')?.text,
|
||||||
|
errorMessage:
|
||||||
|
'Could not parse sentence translation. Is the provided document corrupt, or has Jisho been updated?',
|
||||||
|
);
|
||||||
|
|
||||||
|
final pieces = getPieces(sentenceElement);
|
||||||
|
|
||||||
|
sentenceElement.querySelector('.english')?.remove();
|
||||||
|
|
||||||
|
for (var element in sentenceElement.children[0].children) {
|
||||||
|
element.querySelector('.furigana')?.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
final japanese = sentenceElement.text;
|
||||||
|
return PhraseScrapeSentence(
|
||||||
|
english: english,
|
||||||
|
japanese: japanese,
|
||||||
|
pieces: pieces,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<PhraseScrapeSentence> _getSentences(Element child) {
|
||||||
|
final sentenceElements =
|
||||||
|
child.querySelector('.sentences')?.querySelectorAll('.sentence');
|
||||||
|
if (sentenceElements == null) return [];
|
||||||
|
|
||||||
|
return sentenceElements.map(_getSentence).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
PhraseScrapeMeaning _getMeaning(Element child) {
|
||||||
|
final meaning = _getMeaningString(child);
|
||||||
|
final meaningAbstract = _getMeaningAbstract(child);
|
||||||
|
final supplemental = _getSupplemental(child);
|
||||||
|
final seeAlsoTerms = _getSeeAlsoTerms(supplemental);
|
||||||
|
final sentences = _getSentences(child);
|
||||||
|
|
||||||
|
return PhraseScrapeMeaning(
|
||||||
|
seeAlsoTerms: seeAlsoTerms,
|
||||||
|
sentences: sentences,
|
||||||
|
definition: meaning,
|
||||||
|
supplemental: supplemental,
|
||||||
|
definitionAbstract: meaningAbstract,
|
||||||
|
// tags: mostRecentWordTypes ?? [],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<AudioFile> _getAudio(Document document) {
|
||||||
|
return document
|
||||||
|
.querySelector('.concept_light-status')
|
||||||
|
?.querySelectorAll('audio > source')
|
||||||
|
.map((element) {
|
||||||
|
final src = assertNotNull(
|
||||||
|
variable: element.attributes["src"],
|
||||||
|
errorMessage:
|
||||||
|
'Could not parse audio source. Is the provided document corrupt, or has Jisho been updated?',
|
||||||
|
);
|
||||||
|
final type = assertNotNull(
|
||||||
|
variable: element.attributes['type'],
|
||||||
|
errorMessage:
|
||||||
|
'Could not parse audio type. Is the provided document corrupt, or has Jisho been updated?',
|
||||||
|
);
|
||||||
|
return AudioFile(
|
||||||
|
uri: 'https:$src',
|
||||||
|
mimetype: type,
|
||||||
|
);
|
||||||
|
}).toList() ??
|
||||||
|
[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provides the URI for a phrase scrape
|
||||||
|
Uri uriForPhraseScrape(String searchTerm) {
|
||||||
|
return Uri.parse('https://jisho.org/word/${Uri.encodeComponent(searchTerm)}');
|
||||||
|
}
|
||||||
|
|
||||||
|
PhrasePageScrapeResultData _getMeaningsOtherFormsAndNotes(
|
||||||
|
String query, Document document) {
|
||||||
|
final meaningsWrapper = assertNotNull(
|
||||||
|
variable: document.querySelector('.meanings-wrapper'),
|
||||||
|
errorMessage:
|
||||||
|
"Could not parse meanings. Is the provided document corrupt, or has Jisho been updated?",
|
||||||
|
);
|
||||||
|
|
||||||
|
final meanings = <PhraseScrapeMeaning>[];
|
||||||
|
var mostRecentWordTypes = [];
|
||||||
|
var otherForms;
|
||||||
|
var notes;
|
||||||
|
|
||||||
|
for (var child in meaningsWrapper.children) {
|
||||||
|
if (child.className.contains('meaning-tags')) {
|
||||||
|
mostRecentWordTypes = _getMostRecentWordTypes(child);
|
||||||
|
} else if (mostRecentWordTypes[0] == 'other forms') {
|
||||||
|
otherForms = _getOtherForms(child);
|
||||||
|
} else if (mostRecentWordTypes[0] == 'notes') {
|
||||||
|
notes = _getNotes(child);
|
||||||
|
} else {
|
||||||
|
meanings.add(_getMeaning(child));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PhrasePageScrapeResultData(
|
||||||
|
uri: uriForPhraseScrape(query).toString(),
|
||||||
|
tags: _getTags(document),
|
||||||
|
meanings: meanings,
|
||||||
|
otherForms: otherForms ?? [],
|
||||||
|
audio: _getAudio(document),
|
||||||
|
notes: notes ?? [],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _resultWasFound(Document document) {
|
||||||
|
return document.querySelector('.meanings-wrapper') != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses a jisho word search page to an object
|
||||||
|
PhrasePageScrapeResult parsePhrasePageData(String pageHtml, String query) {
|
||||||
|
final document = parse(pageHtml);
|
||||||
|
|
||||||
|
if (!_resultWasFound(document)) {
|
||||||
|
return PhrasePageScrapeResult(found: false, query: query);
|
||||||
|
}
|
||||||
|
|
||||||
|
final data = _getMeaningsOtherFormsAndNotes(query, document);
|
||||||
|
|
||||||
|
return PhrasePageScrapeResult(
|
||||||
|
found: true,
|
||||||
|
query: query,
|
||||||
|
data: data,
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
import './base_uri.dart';
|
||||||
|
|
||||||
|
/// Provides the URI for a phrase search
|
||||||
|
Uri uriForPhraseSearch(String phrase) {
|
||||||
|
return Uri.parse('$jishoApi?keyword=${Uri.encodeComponent(phrase)}');
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
/// Remove all newlines from a string
|
||||||
|
String removeNewlines(String str) {
|
||||||
|
return str.replaceAll(RegExp(r'(?:\r|\n)'), '').trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove alltext between two positions, and remove all newlines
|
||||||
|
String getStringBetweenIndicies(String data, int startIndex, int endIndex) {
|
||||||
|
final result = data.substring(startIndex, endIndex);
|
||||||
|
return removeNewlines(result).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to find a string between two pieces of text
|
||||||
|
String? getStringBetweenStrings(
|
||||||
|
String data,
|
||||||
|
String startString,
|
||||||
|
String endString,
|
||||||
|
) {
|
||||||
|
final regex = RegExp(
|
||||||
|
'${RegExp.escape(startString)}(.*?)${RegExp.escape(endString)}',
|
||||||
|
dotAll: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
final match = regex.allMatches(data).toList();
|
||||||
|
return match.isNotEmpty ? match[0].group(1).toString() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to find an int inbetween two pieces of text
|
||||||
|
int? getIntBetweenStrings(
|
||||||
|
String data,
|
||||||
|
String startString,
|
||||||
|
String endString,
|
||||||
|
) {
|
||||||
|
final stringBetweenStrings =
|
||||||
|
getStringBetweenStrings(data, startString, endString);
|
||||||
|
return stringBetweenStrings != null ? int.parse(stringBetweenStrings) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get all regex matches
|
||||||
|
List<String> getAllGlobalGroupMatches(String str, RegExp regex) {
|
||||||
|
final regexResults = regex.allMatches(str).toList();
|
||||||
|
final results = <String>[];
|
||||||
|
for (var match in regexResults) {
|
||||||
|
final m = match.group(1);
|
||||||
|
if (m != null) results.add(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get all matches of `<a>DATA</a>`
|
||||||
|
List<String> parseAnchorsToArray(String str) {
|
||||||
|
final regex = RegExp(r'<a href=".*?">(.*?)<\/a>');
|
||||||
|
return getAllGlobalGroupMatches(str, regex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An exception to be thrown whenever a parser fails by not finding an expected pattern.
|
||||||
|
class ParserException implements Exception {
|
||||||
|
/// The error message to report
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
// ignore: public_member_api_docs
|
||||||
|
const ParserException(this.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Throw a `ParserException` if variable is null
|
||||||
|
dynamic assertNotNull({
|
||||||
|
required dynamic variable,
|
||||||
|
String errorMessage =
|
||||||
|
"Unexpected null-value occured. Is the provided document corrupt, or has Jisho been updated?",
|
||||||
|
}) {
|
||||||
|
if (variable == null) {
|
||||||
|
throw ParserException(errorMessage);
|
||||||
|
}
|
||||||
|
return variable!;
|
||||||
|
}
|
18
pubspec.yaml
18
pubspec.yaml
|
@ -1,20 +1,20 @@
|
||||||
name: unofficial_jisho_api
|
name: unofficial_jisho_api
|
||||||
version: 1.1.0
|
version: 2.0.0
|
||||||
|
|
||||||
description: An unofficial api for searching and scraping the japanese dictionary Jisho.org
|
description: An unofficial api for searching and scraping the japanese dictionary Jisho.org
|
||||||
homepage: https://github.com/h7x4ABk3g/unofficial_jisho_api_dart/
|
homepage: https://github.com/h7x4ABk3g/unofficial_jisho_api_dart/
|
||||||
issue_tracker: https://github.com/h7x4ABk3g/unofficial_jisho_api_dart/issues
|
issue_tracker: https://github.com/h7x4ABk3g/unofficial_jisho_api_dart/issues
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.7.0 <3.0.0'
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
http: ^0.12.1
|
http: ^0.13.3
|
||||||
html_unescape: ^1.0.1+3
|
html_unescape: ^2.0.0
|
||||||
html: ^0.14.0+3
|
html: ^0.15.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
pedantic: ^1.9.0
|
pedantic: ^1.11.1
|
||||||
test: ^1.15.0
|
test: ^1.17.10
|
||||||
path: ^1.7.0
|
path: ^1.8.0
|
||||||
effective_dart: ^1.2.3
|
effective_dart: ^1.3.2
|
||||||
|
|
|
@ -7,7 +7,11 @@ import 'package:unofficial_jisho_api/api.dart';
|
||||||
final JsonEncoder encoder = JsonEncoder.withIndent(' ');
|
final JsonEncoder encoder = JsonEncoder.withIndent(' ');
|
||||||
final String currentdir = Directory.current.path;
|
final String currentdir = Directory.current.path;
|
||||||
|
|
||||||
void writeCases(Function apiFunction, String folderName, List<String> queries) async {
|
void writeCases(
|
||||||
|
Function apiFunction,
|
||||||
|
String folderName,
|
||||||
|
List<String> queries,
|
||||||
|
) async {
|
||||||
final dir = path.join(currentdir, 'test', folderName);
|
final dir = path.join(currentdir, 'test', folderName);
|
||||||
|
|
||||||
for (var testCount = 0; testCount < queries.length; testCount++) {
|
for (var testCount = 0; testCount < queries.length; testCount++) {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,6 +2,401 @@
|
||||||
"query": "日本人",
|
"query": "日本人",
|
||||||
"found": true,
|
"found": true,
|
||||||
"results": [
|
"results": [
|
||||||
|
{
|
||||||
|
"english": "After the war, the diligence and the saving of the Japanese gave an impression which is strong in the American.",
|
||||||
|
"kanji": "戦後、日本人の勤勉さと節約はアメリカ人に強い印象を与えた。",
|
||||||
|
"kana": "せんご、にほんじんのきんべんさとせつやくはアメリカじんにつよいいんしょうをあたえた。",
|
||||||
|
"pieces": [
|
||||||
|
{
|
||||||
|
"lifted": "せんご",
|
||||||
|
"unlifted": "戦後"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "にほんじん",
|
||||||
|
"unlifted": "日本人"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "の"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "きんべん",
|
||||||
|
"unlifted": "勤勉さ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "と"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "せつやく",
|
||||||
|
"unlifted": "節約"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "は"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "アメリカじん",
|
||||||
|
"unlifted": "アメリカ人"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "に"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "つよ",
|
||||||
|
"unlifted": "強い"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "いんしょうをあた",
|
||||||
|
"unlifted": "印象を与えた"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"english": "Cleanliness is proper to the Japanese.",
|
||||||
|
"kanji": "清潔は日本人の習性だ。",
|
||||||
|
"kana": "せいけつはにほんじんのしゅうせいだ。",
|
||||||
|
"pieces": [
|
||||||
|
{
|
||||||
|
"lifted": "せいけつ",
|
||||||
|
"unlifted": "清潔"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "は"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "にほんじん",
|
||||||
|
"unlifted": "日本人"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "の"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "しゅうせい",
|
||||||
|
"unlifted": "習性"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "だ"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"english": "The passengers on board were mostly Japanese.",
|
||||||
|
"kanji": "乗船客は主に日本人だった。",
|
||||||
|
"kana": "じょうせんきゃくはおもににほんじんだった。",
|
||||||
|
"pieces": [
|
||||||
|
{
|
||||||
|
"lifted": "じょうせん",
|
||||||
|
"unlifted": "乗船"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "きゃく",
|
||||||
|
"unlifted": "客"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "は"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "おも",
|
||||||
|
"unlifted": "主に"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "にほんじん",
|
||||||
|
"unlifted": "日本人"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "だった"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"english": "Those who are present are all Japanese.",
|
||||||
|
"kanji": "出席をしている人々は全部日本人です。",
|
||||||
|
"kana": "しゅっせきをしているひとびと々はぜんぶにほんじんです。",
|
||||||
|
"pieces": [
|
||||||
|
{
|
||||||
|
"lifted": "しゅっせき",
|
||||||
|
"unlifted": "出席"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "を"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "している"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "ひとびと",
|
||||||
|
"unlifted": "人々"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "は"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "ぜんぶ",
|
||||||
|
"unlifted": "全部"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "にほんじん",
|
||||||
|
"unlifted": "日本人"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "です"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"english": "Some young Japanese people prefer being single to being married.",
|
||||||
|
"kanji": "若い日本人の中には、結婚するより独身でいることを好む者もいる。",
|
||||||
|
"kana": "わかいにほんじんのなかには、けっこんするよりどくしんでいることをこのむものもいる。",
|
||||||
|
"pieces": [
|
||||||
|
{
|
||||||
|
"lifted": "わか",
|
||||||
|
"unlifted": "若い"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "にほんじん",
|
||||||
|
"unlifted": "日本人"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "の"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "なか",
|
||||||
|
"unlifted": "中"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "には"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "けっこん",
|
||||||
|
"unlifted": "結婚する"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "より"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "どくしん",
|
||||||
|
"unlifted": "独身"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "で"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "いる"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "こと"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "を"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "この",
|
||||||
|
"unlifted": "好む"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "もの",
|
||||||
|
"unlifted": "者"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "も"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "いる"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"english": "I didn't know that he was Japanese.",
|
||||||
|
"kanji": "私は彼が日本人だとは知らなかった。",
|
||||||
|
"kana": "わたしはかれがにほんじんだとはしらなかった。",
|
||||||
|
"pieces": [
|
||||||
|
{
|
||||||
|
"lifted": "わたし",
|
||||||
|
"unlifted": "私"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "は"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "かれ",
|
||||||
|
"unlifted": "彼"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "が"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "にほんじん",
|
||||||
|
"unlifted": "日本人"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "だ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "と"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "は"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "し",
|
||||||
|
"unlifted": "知らなかった"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"english": "I speak of the Japanese in general.",
|
||||||
|
"kanji": "私は日本人一般について言っているのだ。",
|
||||||
|
"kana": "わたしはにほんじんいっぱんについていっているのだ。",
|
||||||
|
"pieces": [
|
||||||
|
{
|
||||||
|
"lifted": "わたし",
|
||||||
|
"unlifted": "私"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "は"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "にほんじん",
|
||||||
|
"unlifted": "日本人"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "いっぱん",
|
||||||
|
"unlifted": "一般"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "について"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "い",
|
||||||
|
"unlifted": "言っている"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "のだ"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"english": "I am Japanese, but you are an American.",
|
||||||
|
"kanji": "私は日本人ですが、あなたはアメリカ人です。",
|
||||||
|
"kana": "わたしはにほんじんですが、あなたはアメリカじんです。",
|
||||||
|
"pieces": [
|
||||||
|
{
|
||||||
|
"lifted": "わたし",
|
||||||
|
"unlifted": "私"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "は"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "にほんじん",
|
||||||
|
"unlifted": "日本人"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "です"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "が"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "あなた"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "は"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "アメリカじん",
|
||||||
|
"unlifted": "アメリカ人"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "です"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"english": "I thought only Japanese were workaholics.",
|
||||||
|
"kanji": "私は仕事中毒者は日本人だけかと思っていました。",
|
||||||
|
"kana": "わたしはしごとちゅうどくしゃはにほんじんだけかとおもっていました。",
|
||||||
|
"pieces": [
|
||||||
|
{
|
||||||
|
"lifted": "わたし",
|
||||||
|
"unlifted": "私"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "は"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "しごと",
|
||||||
|
"unlifted": "仕事"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "ちゅうどく",
|
||||||
|
"unlifted": "中毒"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "しゃ",
|
||||||
|
"unlifted": "者"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "は"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "にほんじん",
|
||||||
|
"unlifted": "日本人"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "だけ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "か"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "と"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "おも",
|
||||||
|
"unlifted": "思っていました"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"english": "A Japanese person would never do such a thing.",
|
"english": "A Japanese person would never do such a thing.",
|
||||||
"kanji": "日本人ならそんなことはけっしてしないでしょう。",
|
"kanji": "日本人ならそんなことはけっしてしないでしょう。",
|
||||||
|
@ -41,49 +436,6 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"english": "When did the Japanese start eating polished rice?",
|
|
||||||
"kanji": "いつから日本人は精白米を食べるようになったのですか?",
|
|
||||||
"kana": "いつからにほんじんはせいはくまいをたべるようになったのですか?",
|
|
||||||
"pieces": [
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "いつから"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "にほんじん",
|
|
||||||
"unlifted": "日本人"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "は"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "せいはくまい",
|
|
||||||
"unlifted": "精白米"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "を"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "た",
|
|
||||||
"unlifted": "食べる"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "ようになった"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "のです"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "か"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"english": "I think there are probably few Japanese who know this side of the Emperor Meiji, the side that left a song like this.",
|
"english": "I think there are probably few Japanese who know this side of the Emperor Meiji, the side that left a song like this.",
|
||||||
"kanji": "こんな歌を残している明治天皇の一面を知っている日本人は少ないのではないだろうか。",
|
"kanji": "こんな歌を残している明治天皇の一面を知っている日本人は少ないのではないだろうか。",
|
||||||
|
@ -281,6 +633,53 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"english": "Few Japanese can use English well.",
|
||||||
|
"kanji": "日本人で英語をうまく使える人はほとんどいません。",
|
||||||
|
"kana": "にほんじんでえいごをうまくつかえるひとはほとんどいません。",
|
||||||
|
"pieces": [
|
||||||
|
{
|
||||||
|
"lifted": "にほんじん",
|
||||||
|
"unlifted": "日本人"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "で"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "えいご",
|
||||||
|
"unlifted": "英語"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "を"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "うまく"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "つか",
|
||||||
|
"unlifted": "使える"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": "ひと",
|
||||||
|
"unlifted": "人"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "は"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "ほとんど"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "いません"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"english": "As you can also tell from these beautiful, far from Japanese, looks, Yuna is not pure-blood Japanese. She's a quarter-blood with a westerner as grandmother.",
|
"english": "As you can also tell from these beautiful, far from Japanese, looks, Yuna is not pure-blood Japanese. She's a quarter-blood with a westerner as grandmother.",
|
||||||
"kanji": "日本人離れしたこの美しい相貌からもわかるように、優奈は実は生粋の日本人じゃない。西洋人をおばあちゃんに持つ、クォーターだったりする。",
|
"kanji": "日本人離れしたこの美しい相貌からもわかるように、優奈は実は生粋の日本人じゃない。西洋人をおばあちゃんに持つ、クォーターだったりする。",
|
||||||
|
@ -590,299 +989,7 @@
|
||||||
"unlifted": "雇う"
|
"unlifted": "雇う"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"english": "Are they Japanese?",
|
|
||||||
"kanji": "彼らは日本人ですか。",
|
|
||||||
"kana": "かれらはにほんじんですか。",
|
|
||||||
"pieces": [
|
|
||||||
{
|
|
||||||
"lifted": "かれ",
|
|
||||||
"unlifted": "彼ら"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "は"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "にほんじん",
|
|
||||||
"unlifted": "日本人"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "ですか"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"english": "Are they Japanese or Chinese?",
|
|
||||||
"kanji": "彼らは日本人ですか、それとも中国人ですか。",
|
|
||||||
"kana": "かれらはにほんじんですか、それともちゅうごくじんですか。",
|
|
||||||
"pieces": [
|
|
||||||
{
|
|
||||||
"lifted": "かれ",
|
|
||||||
"unlifted": "彼ら"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "は"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "にほんじん",
|
|
||||||
"unlifted": "日本人"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "ですか"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "それとも"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "ちゅうごくじん",
|
|
||||||
"unlifted": "中国人"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "ですか"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"english": "He is not Japanese.",
|
|
||||||
"kanji": "彼は日本人ではありません。",
|
|
||||||
"kana": "かれはにほんじんではありません。",
|
|
||||||
"pieces": [
|
|
||||||
{
|
|
||||||
"lifted": "かれ",
|
|
||||||
"unlifted": "彼"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "は"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "にほんじん",
|
|
||||||
"unlifted": "日本人"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "ではありません"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"english": "He speaks Japanese as if he were Japanese.",
|
|
||||||
"kanji": "彼は日本語をまるで日本人であるかのように話す。",
|
|
||||||
"kana": "かれはにほんごをまるでにほんじんであるかのようにはなす。",
|
|
||||||
"pieces": [
|
|
||||||
{
|
|
||||||
"lifted": "かれ",
|
|
||||||
"unlifted": "彼"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "は"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "にほんご",
|
|
||||||
"unlifted": "日本語"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "を"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "まるで"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "にほんじん",
|
|
||||||
"unlifted": "日本人"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "である"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "かのように"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "はな",
|
|
||||||
"unlifted": "話す"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"english": "He is a typical Japanese.",
|
|
||||||
"kanji": "彼は典型的な日本人だ。",
|
|
||||||
"kana": "かれはてんけいてきなにほんじんだ。",
|
|
||||||
"pieces": [
|
|
||||||
{
|
|
||||||
"lifted": "かれ",
|
|
||||||
"unlifted": "彼"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "は"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "てんけいてき",
|
|
||||||
"unlifted": "典型的な"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "にほんじん",
|
|
||||||
"unlifted": "日本人"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "だ"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"english": "He is Japanese by birth.",
|
|
||||||
"kanji": "彼は生まれは日本人です。",
|
|
||||||
"kana": "かれはうまれはにほんじんです。",
|
|
||||||
"pieces": [
|
|
||||||
{
|
|
||||||
"lifted": "かれ",
|
|
||||||
"unlifted": "彼"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "は"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "う",
|
|
||||||
"unlifted": "生まれ"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "は"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "にほんじん",
|
|
||||||
"unlifted": "日本人"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "です"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"english": "He is the first Japanese that traveled in space.",
|
|
||||||
"kanji": "彼は最初に宇宙旅行をした日本人です。",
|
|
||||||
"kana": "かれはさいしょにうちゅうりょこうをしたにほんじんです。",
|
|
||||||
"pieces": [
|
|
||||||
{
|
|
||||||
"lifted": "かれ",
|
|
||||||
"unlifted": "彼"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "は"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "さいしょ",
|
|
||||||
"unlifted": "最初"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "に"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "うちゅうりょこう",
|
|
||||||
"unlifted": "宇宙旅行"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "を"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "した"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "にほんじん",
|
|
||||||
"unlifted": "日本人"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "です"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"english": "He is Japanese to the bone.",
|
|
||||||
"kanji": "彼は骨の髄まで日本人だ。",
|
|
||||||
"kana": "かれはほねのずいまでにほんじんだ。",
|
|
||||||
"pieces": [
|
|
||||||
{
|
|
||||||
"lifted": "かれ",
|
|
||||||
"unlifted": "彼"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "は"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "ほねのずい",
|
|
||||||
"unlifted": "骨の髄まで"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "にほんじん",
|
|
||||||
"unlifted": "日本人"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "だ"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"english": "He speaks Japanese as if he were Japanese.",
|
|
||||||
"kanji": "彼は、日本語をまるで日本人かのように話す。",
|
|
||||||
"kana": "かれは、にほんごをまるでにほんじんかのようにはなす。",
|
|
||||||
"pieces": [
|
|
||||||
{
|
|
||||||
"lifted": "かれ",
|
|
||||||
"unlifted": "彼"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "は"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "にほんご",
|
|
||||||
"unlifted": "日本語"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "を"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "まるで"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "にほんじん",
|
|
||||||
"unlifted": "日本人"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "かのように"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "はな",
|
|
||||||
"unlifted": "話す"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"uri": "https://jisho.org/search/%E6%97%A5%E6%9C%AC%E4%BA%BA%23sentences",
|
"uri": "https://jisho.org/search/%E6%97%A5%E6%9C%AC%E4%BA%BA%23sentences"
|
||||||
"phrase": "日本人"
|
|
||||||
}
|
}
|
|
@ -2,6 +2,5 @@
|
||||||
"query": "彼*叩く",
|
"query": "彼*叩く",
|
||||||
"found": false,
|
"found": false,
|
||||||
"results": [],
|
"results": [],
|
||||||
"uri": "https://jisho.org/search/%E5%BD%BC%EF%BC%8A%E5%8F%A9%E3%81%8F%23sentences",
|
"uri": "https://jisho.org/search/%E5%BD%BC%EF%BC%8A%E5%8F%A9%E3%81%8F%23sentences"
|
||||||
"phrase": "彼*叩く"
|
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -2,6 +2,5 @@
|
||||||
"query": "ネガティブ",
|
"query": "ネガティブ",
|
||||||
"found": false,
|
"found": false,
|
||||||
"results": [],
|
"results": [],
|
||||||
"uri": "https://jisho.org/search/%E3%83%8D%E3%82%AC%E3%83%86%E3%82%A3%E3%83%96%23sentences",
|
"uri": "https://jisho.org/search/%E3%83%8D%E3%82%AC%E3%83%86%E3%82%A3%E3%83%96%23sentences"
|
||||||
"phrase": "ネガティブ"
|
|
||||||
}
|
}
|
|
@ -2,6 +2,5 @@
|
||||||
"query": "grlgmregmneriireg",
|
"query": "grlgmregmneriireg",
|
||||||
"found": false,
|
"found": false,
|
||||||
"results": [],
|
"results": [],
|
||||||
"uri": "https://jisho.org/search/grlgmregmneriireg%23sentences",
|
"uri": "https://jisho.org/search/grlgmregmneriireg%23sentences"
|
||||||
"phrase": "grlgmregmneriireg"
|
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"query": "車",
|
"query": "車",
|
||||||
"found": true,
|
"found": true,
|
||||||
|
"data": {
|
||||||
"taughtIn": "grade 1",
|
"taughtIn": "grade 1",
|
||||||
"jlptLevel": "N5",
|
"jlptLevel": "N5",
|
||||||
"newspaperFrequencyRank": 333,
|
"newspaperFrequencyRank": 333,
|
||||||
|
@ -53,7 +54,7 @@
|
||||||
],
|
],
|
||||||
"radical": {
|
"radical": {
|
||||||
"symbol": "車",
|
"symbol": "車",
|
||||||
"forms": null,
|
"forms": [],
|
||||||
"meaning": "cart, car"
|
"meaning": "cart, car"
|
||||||
},
|
},
|
||||||
"parts": [
|
"parts": [
|
||||||
|
@ -64,3 +65,4 @@
|
||||||
"strokeOrderGifUri": "https://raw.githubusercontent.com/mistval/kanji_images/master/gifs/8eca.gif",
|
"strokeOrderGifUri": "https://raw.githubusercontent.com/mistval/kanji_images/master/gifs/8eca.gif",
|
||||||
"uri": "https://jisho.org/search/%E8%BB%8A%23kanji"
|
"uri": "https://jisho.org/search/%E8%BB%8A%23kanji"
|
||||||
}
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"query": "家",
|
"query": "家",
|
||||||
"found": true,
|
"found": true,
|
||||||
|
"data": {
|
||||||
"taughtIn": "grade 2",
|
"taughtIn": "grade 2",
|
||||||
"jlptLevel": "N4",
|
"jlptLevel": "N4",
|
||||||
"newspaperFrequencyRank": 133,
|
"newspaperFrequencyRank": 133,
|
||||||
|
@ -101,17 +102,17 @@
|
||||||
{
|
{
|
||||||
"example": "家",
|
"example": "家",
|
||||||
"reading": "うち",
|
"reading": "うち",
|
||||||
"meaning": "house, home (one's own), (one's) family, (one's) household"
|
"meaning": "house, one's house, one's home, one's family, one's household"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"example": "家中",
|
"example": "家中",
|
||||||
"reading": "うちじゅう",
|
"reading": "うちじゅう",
|
||||||
"meaning": "whole family, all (members of) the family, all over the house, retainer of a daimyo, feudal domain, clan"
|
"meaning": "whole family, entire family, all (members of) the family, all over the house, throughout the house, retainer of a daimyo, feudal domain, clan"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"radical": {
|
"radical": {
|
||||||
"symbol": "宀",
|
"symbol": "宀",
|
||||||
"forms": null,
|
"forms": [],
|
||||||
"meaning": "roof"
|
"meaning": "roof"
|
||||||
},
|
},
|
||||||
"parts": [
|
"parts": [
|
||||||
|
@ -123,3 +124,4 @@
|
||||||
"strokeOrderGifUri": "https://raw.githubusercontent.com/mistval/kanji_images/master/gifs/5bb6.gif",
|
"strokeOrderGifUri": "https://raw.githubusercontent.com/mistval/kanji_images/master/gifs/5bb6.gif",
|
||||||
"uri": "https://jisho.org/search/%E5%AE%B6%23kanji"
|
"uri": "https://jisho.org/search/%E5%AE%B6%23kanji"
|
||||||
}
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"query": "楽",
|
"query": "楽",
|
||||||
"found": true,
|
"found": true,
|
||||||
|
"data": {
|
||||||
"taughtIn": "grade 2",
|
"taughtIn": "grade 2",
|
||||||
"jlptLevel": "N4",
|
"jlptLevel": "N4",
|
||||||
"newspaperFrequencyRank": 373,
|
"newspaperFrequencyRank": 373,
|
||||||
|
@ -18,9 +19,9 @@
|
||||||
],
|
],
|
||||||
"onyomiExamples": [
|
"onyomiExamples": [
|
||||||
{
|
{
|
||||||
"example": "楽団",
|
"example": "楽",
|
||||||
"reading": "ガクダン",
|
"reading": "ガク",
|
||||||
"meaning": "orchestra, band"
|
"meaning": "music, old Japanese court music, gagaku"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"example": "楽章",
|
"example": "楽章",
|
||||||
|
@ -40,12 +41,12 @@
|
||||||
{
|
{
|
||||||
"example": "楽",
|
"example": "楽",
|
||||||
"reading": "ラク",
|
"reading": "ラク",
|
||||||
"meaning": "comfort, ease, relief, (at) peace, relaxation, easy, simple, without trouble, without hardships, (economically) comfortable, raku pottery"
|
"meaning": "comfort, ease, relief, (at) peace, relaxation, easy, simple, without trouble, without hardships, (economically) comfortable, raku pottery, sukha (happiness)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"example": "楽園",
|
"example": "楽園",
|
||||||
"reading": "ラクエン",
|
"reading": "ラクエン",
|
||||||
"meaning": "pleasure garden, paradise"
|
"meaning": "paradise, Eden, Elysium"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"example": "千秋楽",
|
"example": "千秋楽",
|
||||||
|
@ -82,7 +83,7 @@
|
||||||
],
|
],
|
||||||
"radical": {
|
"radical": {
|
||||||
"symbol": "木",
|
"symbol": "木",
|
||||||
"forms": null,
|
"forms": [],
|
||||||
"meaning": "tree"
|
"meaning": "tree"
|
||||||
},
|
},
|
||||||
"parts": [
|
"parts": [
|
||||||
|
@ -95,3 +96,4 @@
|
||||||
"strokeOrderGifUri": "https://raw.githubusercontent.com/mistval/kanji_images/master/gifs/697d.gif",
|
"strokeOrderGifUri": "https://raw.githubusercontent.com/mistval/kanji_images/master/gifs/697d.gif",
|
||||||
"uri": "https://jisho.org/search/%E6%A5%BD%23kanji"
|
"uri": "https://jisho.org/search/%E6%A5%BD%23kanji"
|
||||||
}
|
}
|
||||||
|
}
|
|
@ -1,19 +1,5 @@
|
||||||
{
|
{
|
||||||
"query": "極上",
|
"query": "極上",
|
||||||
"found": false,
|
"found": false,
|
||||||
"taughtIn": null,
|
"data": null
|
||||||
"jlptLevel": null,
|
|
||||||
"newspaperFrequencyRank": null,
|
|
||||||
"strokeCount": null,
|
|
||||||
"meaning": null,
|
|
||||||
"kunyomi": null,
|
|
||||||
"onyomi": null,
|
|
||||||
"onyomiExamples": null,
|
|
||||||
"kunyomiExamples": null,
|
|
||||||
"radical": null,
|
|
||||||
"parts": null,
|
|
||||||
"strokeOrderDiagramUri": null,
|
|
||||||
"strokeOrderSvgUri": null,
|
|
||||||
"strokeOrderGifUri": null,
|
|
||||||
"uri": null
|
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"query": "贄",
|
"query": "贄",
|
||||||
"found": true,
|
"found": true,
|
||||||
|
"data": {
|
||||||
"taughtIn": null,
|
"taughtIn": null,
|
||||||
"jlptLevel": null,
|
"jlptLevel": null,
|
||||||
"newspaperFrequencyRank": null,
|
"newspaperFrequencyRank": null,
|
||||||
|
@ -32,7 +33,7 @@
|
||||||
],
|
],
|
||||||
"radical": {
|
"radical": {
|
||||||
"symbol": "貝",
|
"symbol": "貝",
|
||||||
"forms": null,
|
"forms": [],
|
||||||
"meaning": "shell"
|
"meaning": "shell"
|
||||||
},
|
},
|
||||||
"parts": [
|
"parts": [
|
||||||
|
@ -51,3 +52,4 @@
|
||||||
"strokeOrderGifUri": "https://raw.githubusercontent.com/mistval/kanji_images/master/gifs/8d04.gif",
|
"strokeOrderGifUri": "https://raw.githubusercontent.com/mistval/kanji_images/master/gifs/8d04.gif",
|
||||||
"uri": "https://jisho.org/search/%E8%B4%84%23kanji"
|
"uri": "https://jisho.org/search/%E8%B4%84%23kanji"
|
||||||
}
|
}
|
||||||
|
}
|
|
@ -1,19 +1,5 @@
|
||||||
{
|
{
|
||||||
"query": "ネガティブ",
|
"query": "ネガティブ",
|
||||||
"found": false,
|
"found": false,
|
||||||
"taughtIn": null,
|
"data": null
|
||||||
"jlptLevel": null,
|
|
||||||
"newspaperFrequencyRank": null,
|
|
||||||
"strokeCount": null,
|
|
||||||
"meaning": null,
|
|
||||||
"kunyomi": null,
|
|
||||||
"onyomi": null,
|
|
||||||
"onyomiExamples": null,
|
|
||||||
"kunyomiExamples": null,
|
|
||||||
"radical": null,
|
|
||||||
"parts": null,
|
|
||||||
"strokeOrderDiagramUri": null,
|
|
||||||
"strokeOrderSvgUri": null,
|
|
||||||
"strokeOrderGifUri": null,
|
|
||||||
"uri": null
|
|
||||||
}
|
}
|
|
@ -1,19 +1,5 @@
|
||||||
{
|
{
|
||||||
"query": "wegmwrlgkrgmg",
|
"query": "wegmwrlgkrgmg",
|
||||||
"found": false,
|
"found": false,
|
||||||
"taughtIn": null,
|
"data": null
|
||||||
"jlptLevel": null,
|
|
||||||
"newspaperFrequencyRank": null,
|
|
||||||
"strokeCount": null,
|
|
||||||
"meaning": null,
|
|
||||||
"kunyomi": null,
|
|
||||||
"onyomi": null,
|
|
||||||
"onyomiExamples": null,
|
|
||||||
"kunyomiExamples": null,
|
|
||||||
"radical": null,
|
|
||||||
"parts": null,
|
|
||||||
"strokeOrderDiagramUri": null,
|
|
||||||
"strokeOrderSvgUri": null,
|
|
||||||
"strokeOrderGifUri": null,
|
|
||||||
"uri": null
|
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"query": "水",
|
"query": "水",
|
||||||
"found": true,
|
"found": true,
|
||||||
|
"data": {
|
||||||
"taughtIn": "grade 1",
|
"taughtIn": "grade 1",
|
||||||
"jlptLevel": "N5",
|
"jlptLevel": "N5",
|
||||||
"newspaperFrequencyRank": 223,
|
"newspaperFrequencyRank": 223,
|
||||||
|
@ -73,3 +74,4 @@
|
||||||
"strokeOrderGifUri": "https://raw.githubusercontent.com/mistval/kanji_images/master/gifs/6c34.gif",
|
"strokeOrderGifUri": "https://raw.githubusercontent.com/mistval/kanji_images/master/gifs/6c34.gif",
|
||||||
"uri": "https://jisho.org/search/%E6%B0%B4%23kanji"
|
"uri": "https://jisho.org/search/%E6%B0%B4%23kanji"
|
||||||
}
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"found": true,
|
"found": true,
|
||||||
"query": "車",
|
"query": "車",
|
||||||
|
"data": {
|
||||||
"uri": "https://jisho.org/word/%E8%BB%8A",
|
"uri": "https://jisho.org/word/%E8%BB%8A",
|
||||||
"tags": [
|
"tags": [
|
||||||
"Common word",
|
"Common word",
|
||||||
|
@ -77,9 +78,7 @@
|
||||||
"definition": "car; automobile; vehicle",
|
"definition": "car; automobile; vehicle",
|
||||||
"supplemental": [],
|
"supplemental": [],
|
||||||
"definitionAbstract": null,
|
"definitionAbstract": null,
|
||||||
"tags": [
|
"tags": []
|
||||||
"noun"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"seeAlsoTerms": [],
|
"seeAlsoTerms": [],
|
||||||
|
@ -87,11 +86,20 @@
|
||||||
"definition": "wheel",
|
"definition": "wheel",
|
||||||
"supplemental": [],
|
"supplemental": [],
|
||||||
"definitionAbstract": null,
|
"definitionAbstract": null,
|
||||||
"tags": [
|
"tags": []
|
||||||
"noun"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"otherForms": [],
|
"otherForms": [],
|
||||||
|
"audio": [
|
||||||
|
{
|
||||||
|
"uri": "https://d1vjc5dkcd3yh2.cloudfront.net/audio/7f47c2a8e633ca3a79ac199f55a212dd.mp3",
|
||||||
|
"mimetype": "audio/mpeg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uri": "https://d1vjc5dkcd3yh2.cloudfront.net/audio_ogg/7f47c2a8e633ca3a79ac199f55a212dd.ogg",
|
||||||
|
"mimetype": "audio/ogg"
|
||||||
|
}
|
||||||
|
],
|
||||||
"notes": []
|
"notes": []
|
||||||
}
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"found": true,
|
"found": true,
|
||||||
"query": "日本人",
|
"query": "日本人",
|
||||||
|
"data": {
|
||||||
"uri": "https://jisho.org/word/%E6%97%A5%E6%9C%AC%E4%BA%BA",
|
"uri": "https://jisho.org/word/%E6%97%A5%E6%9C%AC%E4%BA%BA",
|
||||||
"tags": [
|
"tags": [
|
||||||
"Common word"
|
"Common word"
|
||||||
|
@ -12,9 +13,7 @@
|
||||||
"definition": "Japanese person; Japanese people",
|
"definition": "Japanese person; Japanese people",
|
||||||
"supplemental": [],
|
"supplemental": [],
|
||||||
"definitionAbstract": null,
|
"definitionAbstract": null,
|
||||||
"tags": [
|
"tags": []
|
||||||
"noun"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"seeAlsoTerms": [],
|
"seeAlsoTerms": [],
|
||||||
|
@ -22,9 +21,7 @@
|
||||||
"definition": "Japanese people",
|
"definition": "Japanese people",
|
||||||
"supplemental": [],
|
"supplemental": [],
|
||||||
"definitionAbstract": "The Japanese people are a nationality originating in the Japanese archipelago and are the predominant ethnic group of Japan. Worldwide, approximately 130 million people are of Japanese descent; of these, approximately 127 million are residents of Japan. People of Japanese ancestry who live in other countries are referred to as nikkeijin . The term ethnic Japanese may also be used in some contexts to refer to a locus of ethnic groups including the Yamato, Ainu and Ryukyuan people.",
|
"definitionAbstract": "The Japanese people are a nationality originating in the Japanese archipelago and are the predominant ethnic group of Japan. Worldwide, approximately 130 million people are of Japanese descent; of these, approximately 127 million are residents of Japan. People of Japanese ancestry who live in other countries are referred to as nikkeijin . The term ethnic Japanese may also be used in some contexts to refer to a locus of ethnic groups including the Yamato, Ainu and Ryukyuan people.",
|
||||||
"tags": [
|
"tags": []
|
||||||
"wikipedia definition"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"otherForms": [
|
"otherForms": [
|
||||||
|
@ -33,5 +30,7 @@
|
||||||
"kana": "にっぽんじん"
|
"kana": "にっぽんじん"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"audio": [],
|
||||||
"notes": []
|
"notes": []
|
||||||
}
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"found": true,
|
"found": true,
|
||||||
"query": "皆",
|
"query": "皆",
|
||||||
|
"data": {
|
||||||
"uri": "https://jisho.org/word/%E7%9A%86",
|
"uri": "https://jisho.org/word/%E7%9A%86",
|
||||||
"tags": [
|
"tags": [
|
||||||
"Common word",
|
"Common word",
|
||||||
|
@ -11,64 +12,49 @@
|
||||||
"seeAlsoTerms": [],
|
"seeAlsoTerms": [],
|
||||||
"sentences": [
|
"sentences": [
|
||||||
{
|
{
|
||||||
"english": "The people which were here have all gone.",
|
"english": "She is loved by everybody.",
|
||||||
"japanese": "ここにいた人々はみんな行ってしまった。",
|
"japanese": "彼女はみんなに愛されている。",
|
||||||
"pieces": [
|
"pieces": [
|
||||||
|
{
|
||||||
|
"lifted": "かのじょ",
|
||||||
|
"unlifted": "彼女"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"lifted": null,
|
"lifted": null,
|
||||||
"unlifted": "ここ"
|
"unlifted": "は"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifted": null,
|
||||||
|
"unlifted": "みんな"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"lifted": null,
|
"lifted": null,
|
||||||
"unlifted": "に"
|
"unlifted": "に"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"lifted": null,
|
"lifted": "あい",
|
||||||
"unlifted": "いた"
|
"unlifted": "愛されている"
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "ひとびと",
|
|
||||||
"unlifted": "人々"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "は"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "みんな"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "い",
|
|
||||||
"unlifted": "行って"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "しまった"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"definition": "all; everyone; everybody",
|
"definition": "everyone; everybody; all",
|
||||||
"supplemental": [
|
"supplemental": [
|
||||||
"Usually written using kana alone"
|
"Usually written using kana alone"
|
||||||
],
|
],
|
||||||
"definitionAbstract": null,
|
"definitionAbstract": null,
|
||||||
"tags": [
|
"tags": []
|
||||||
"adverb",
|
|
||||||
"noun"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"seeAlsoTerms": [],
|
"seeAlsoTerms": [],
|
||||||
"sentences": [
|
"sentences": [
|
||||||
{
|
{
|
||||||
"english": "All the dinner had been eaten before he came.",
|
"english": "The leaves have all fallen.",
|
||||||
"japanese": "ごちそうはみんな彼が来ないうちに食べられてしまった。",
|
"japanese": "木の葉はみんな落ちてしまった。",
|
||||||
"pieces": [
|
"pieces": [
|
||||||
{
|
{
|
||||||
"lifted": null,
|
"lifted": "このは",
|
||||||
"unlifted": "ごちそう"
|
"unlifted": "木の葉"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"lifted": null,
|
"lifted": null,
|
||||||
|
@ -79,24 +65,8 @@
|
||||||
"unlifted": "みんな"
|
"unlifted": "みんな"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"lifted": "かれ",
|
"lifted": "お",
|
||||||
"unlifted": "彼"
|
"unlifted": "落ちて"
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "が"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "らい",
|
|
||||||
"unlifted": "来"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": null,
|
|
||||||
"unlifted": "ないうちに"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"lifted": "た",
|
|
||||||
"unlifted": "食べられて"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"lifted": null,
|
"lifted": null,
|
||||||
|
@ -105,15 +75,12 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"definition": "everything",
|
"definition": "everything; all",
|
||||||
"supplemental": [
|
"supplemental": [
|
||||||
"Usually written using kana alone"
|
"Usually written using kana alone"
|
||||||
],
|
],
|
||||||
"definitionAbstract": null,
|
"definitionAbstract": null,
|
||||||
"tags": [
|
"tags": []
|
||||||
"adverb",
|
|
||||||
"noun"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"otherForms": [
|
"otherForms": [
|
||||||
|
@ -126,7 +93,9 @@
|
||||||
"kana": "みな"
|
"kana": "みな"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"audio": [],
|
||||||
"notes": [
|
"notes": [
|
||||||
"皆んな: Irregular okurigana usage."
|
"皆んな: Irregular okurigana usage."
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"found": true,
|
"found": true,
|
||||||
"query": "ネガティブ",
|
"query": "ネガティブ",
|
||||||
|
"data": {
|
||||||
"uri": "https://jisho.org/word/%E3%83%8D%E3%82%AC%E3%83%86%E3%82%A3%E3%83%96",
|
"uri": "https://jisho.org/word/%E3%83%8D%E3%82%AC%E3%83%86%E3%82%A3%E3%83%96",
|
||||||
"tags": [
|
"tags": [
|
||||||
"Common word"
|
"Common word"
|
||||||
|
@ -14,19 +15,17 @@
|
||||||
"Antonym: ポジティブ"
|
"Antonym: ポジティブ"
|
||||||
],
|
],
|
||||||
"definitionAbstract": null,
|
"definitionAbstract": null,
|
||||||
"tags": [
|
"tags": []
|
||||||
"na-adjective"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"seeAlsoTerms": [],
|
"seeAlsoTerms": [],
|
||||||
"sentences": [],
|
"sentences": [],
|
||||||
"definition": "negative (photography)",
|
"definition": "negative",
|
||||||
"supplemental": [],
|
"supplemental": [
|
||||||
|
"Photography"
|
||||||
|
],
|
||||||
"definitionAbstract": null,
|
"definitionAbstract": null,
|
||||||
"tags": [
|
"tags": []
|
||||||
"noun"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"seeAlsoTerms": [
|
"seeAlsoTerms": [
|
||||||
|
@ -36,9 +35,7 @@
|
||||||
"definition": "negative (electrical polarity)",
|
"definition": "negative (electrical polarity)",
|
||||||
"supplemental": [],
|
"supplemental": [],
|
||||||
"definitionAbstract": null,
|
"definitionAbstract": null,
|
||||||
"tags": [
|
"tags": []
|
||||||
"noun"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"seeAlsoTerms": [],
|
"seeAlsoTerms": [],
|
||||||
|
@ -46,9 +43,7 @@
|
||||||
"definition": "Negative (Finnish band)",
|
"definition": "Negative (Finnish band)",
|
||||||
"supplemental": [],
|
"supplemental": [],
|
||||||
"definitionAbstract": "Negative is a Finnish glam rock band founded at the end of 1997. Members of Negative cite musical influence such as Guns N' Roses, Queen, and Hanoi Rocks. The band itself labels the music as ”emotional rock’n roll”.",
|
"definitionAbstract": "Negative is a Finnish glam rock band founded at the end of 1997. Members of Negative cite musical influence such as Guns N' Roses, Queen, and Hanoi Rocks. The band itself labels the music as ”emotional rock’n roll”.",
|
||||||
"tags": [
|
"tags": []
|
||||||
"wikipedia definition"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"otherForms": [
|
"otherForms": [
|
||||||
|
@ -65,5 +60,7 @@
|
||||||
"kana": null
|
"kana": null
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"audio": [],
|
||||||
"notes": []
|
"notes": []
|
||||||
}
|
}
|
||||||
|
}
|
|
@ -1,9 +1,5 @@
|
||||||
{
|
{
|
||||||
"found": false,
|
"found": false,
|
||||||
"query": "grlgmregmneriireg",
|
"query": "grlgmregmneriireg",
|
||||||
"uri": null,
|
"data": null
|
||||||
"tags": null,
|
|
||||||
"meanings": null,
|
|
||||||
"otherForms": null,
|
|
||||||
"notes": null
|
|
||||||
}
|
}
|
|
@ -1,15 +1,17 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:path/path.dart' as path;
|
|
||||||
|
|
||||||
import 'package:unofficial_jisho_api/api.dart';
|
import 'package:path/path.dart' as path;
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
import 'package:unofficial_jisho_api/api.dart';
|
||||||
|
|
||||||
List<String> getFilePaths(String dirname) {
|
List<String> getFilePaths(String dirname) {
|
||||||
final currentdir = Directory.current.path;
|
final currentdir = Directory.current.path;
|
||||||
final testDir = path.join(currentdir, 'test', dirname);
|
final testDir = path.join(currentdir, 'test', dirname);
|
||||||
final filenames = Directory(testDir).listSync();
|
final filenames = Directory(testDir).listSync();
|
||||||
return filenames.map((filename) => path.join(testDir, filename.path)).toList();
|
return filenames
|
||||||
|
.map((filename) => path.join(testDir, filename.path))
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
List getTestCases(String directoryName) {
|
List getTestCases(String directoryName) {
|
||||||
|
|
Loading…
Reference in New Issue