Browse Source

Феминизатор v2.0

master
Maxim Likhachev 6 years ago
parent
commit
9493070dbb
  1. 416
      js/feminitives-functions.js
  2. 449
      js/feminitives-rules.js
  3. 497
      js/feminitives.js
  4. 0
      js/html2canvas.js

416
js/feminitives-functions.js

@ -0,0 +1,416 @@
//
// Copyright (C) 2016-2019, Maxim Lihachev, <envrm@yandex.ru>
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <https://www.gnu.org/licenses/>.
//
//------------------------------------------------------------------------------
'use strict';
//------------------------------------------------------------------------------
//Иерархия элементов на странице
var HTML = {
container: "",
_select: function(element) { return document.getElementById(this.container + "-" + element); },
input: function() { return this._select("word"); },
button: function() { return this._select("convert"); },
dict: function() { return this._select("dict"); },
content: function() { return this._select("content"); },
full: function() { return this._select("full"); },
help: function() { return this._select("help"); },
image: function() { return this._select("image"); },
};
//Вывод справки с примерами использования
function show_help() {
HTML.vis(HTML.help());
HTML.vis(HTML.content());
}
//Смена названия по клику
function swap_title(id) {
var e = document.getElementById(id);
if(e.style.display == 'inline') {
e.style.display = 'none';
} else {
e.style.display = 'inline';
}
}
HTML.vis = function(e, v) {
if (v !== undefined) {
e.style.visibility = v;
} else {
e.style.visibility = e.style.visibility === "visible" ? "hidden" : "visible";
}
}
//Инициализация документа
HTML.init = function(root) {
//Задание базового id для всех элементов
this.container = root;
//Конвертирование по нажатию <Enter>
this.input().addEventListener('keyup', event => {
event.preventDefault();
event.keyCode == 13 && tr();
});
//Конвертирование по нажатию кнопки
this.button().onclick = () => tr();
};
//------------------------------------------------------------------------------
FEM.words.convert = function(string) {
for (var fem_w in this) {
string = string.replace(new RegExp('(^|\\s)+' + fem_w, "ig"), '$1' + this[fem_w])
.replace(/(.)/, s => s.toUpperCase());
}
return string;
};
//------------------------------------------------------------------------------
//Первый элемент списка - окончание (в виде регулярного выражения)
let ending = tuple => new RegExp("^.*" + tuple[0] + "$", "i");
//Второй элемент списка - смещение
let offset = tuple => tuple[1];
//Случайный элемент списка
let random_word = wordlist => wordlist[Math.floor(Math.random() * wordlist.length)];
//Оборачивание в <span> с указанным классом
let html_wrap = (str, cl) => `<span class="${cl}">${str}</span>`;
//Цветовое выделение текста
let css_end = ending => html_wrap(ending, "ending");
//Символ gender gap
let css_gender_gap = html_wrap(' \u26A7 ', "queer");
//------------------------------------------------------------------------------
//Конструирование феминитива с gender_gap
function construct_feminitive(stem, ending, gap) {
return gap ? stem + css_gender_gap + css_end(ending) : stem + "_" + ending;
}
//Длина шаблона, подпадающего под регулярное выражение r
function regex_len(r) {
return r.replace(/\[[^\[\]]*\]/g, "x").length;
}
//Отправка адреса страницы в vk.com
function share_page() {
let vk_url = "http://vk.com/share.php"
+ "?url=" + URL.href
+ "&title=" + URL.title
+ "&description=" + URL.description.text;
let new_tab = window.open(vk_url,'_blank');
new_tab.focus();
}
//Сохранение изображения с феминитивом
function download_image() {
html2canvas(HTML.image(), {
onrendered: canvas => {
let a = document.createElement('a');
a.href = canvas.toDataURL();
a.download = HTML.content().innerHTML + '.png';
a.click();
}
});
}
//Создание феминитива
function make_feminitives(word, visibleGaps) {
//Обрабатываем только слова длиннее трёх символов
if (word.length < 3) return [word, word];
if (FEM.words[word] != undefined) {
let wrd = visibleGaps ? FEM.words[word] : FEM.words[word].replace("_", "");
return [wrd, wrd];
}
var stem = ""; //Основа слова
// var current_ending = word.slice(-2); //Текущее окончание
var current_endings = [word.slice(-4), word.slice(-3), word.slice(-2)];
var feminitives = []; //Массив феминитивов
var femicards = []; //Массив феминитивов для карточки
var found = false;
current_endings.forEach(current_ending => {
if (!found) {
for (let fem_ending in FEM.endings) {
FEM.endings[fem_ending].forEach(end => {
if (regex_len(end[0]) === current_ending.length
&& ending(end).test(current_ending)) {
//Удаление лишних букв из основы
stem = offset(end) === 0 ? word : word.slice(0, -offset(end));
let rule = fem_ending.split("+");
let prefix, all_fem_endings;
if (rule.length > 1) {
prefix = rule[0];
all_fem_endings = rule[1];
} else {
prefix = "";
all_fem_endings = fem_ending;
}
all_fem_endings.split("|").forEach(e => {
//Добавление фем-варианта слова в массив
feminitives.push(construct_feminitive(stem + prefix, e, 1, visibleGaps));
femicards.push(construct_feminitive(stem + prefix, e, 0, visibleGaps));
});
found = true;
}
});
}
}
});
//При отсутствии феминитивов считать корректным исходное слово
return [FEM.random_word(femicards) || word, feminitives];
}
//Создание феминитива
function make_feminitives_old(word) {
//Обрабатываем только слова длиннее трёх символов
if (word.length < 3) return [word, word];
var stem = ""; //Основа слова
var current_ending = word.slice(-2); //Текущее окончание
var feminitives = []; //Массив феминитивов
var femicards = []; //Массив феминитивов для карточки
for (let fem_ending in FEM.endings) {
FEM.endings[fem_ending].forEach(end => {
if (ending(end).test(current_ending)) {
//Удаление лишних букв из основы
stem = offset(end) === 0 ? word : word.slice(0, -offset(end));
//Добавление фем-варианта слова в массив
feminitives.push(construct_feminitive(stem, fem_ending, 1));
femicards.push(construct_feminitive(stem, fem_ending, 0));
}
});
}
//При отсутствии феминитивов считать корректным исходное слово
return [random_word(femicards) || word, feminitives];
}
//Поиск и феминизация дефиниции в викистранице
function parseWikiPage(page) {
var wiki = page.split('\n');
var definition = "";
wiki.some((line, n) => {
if (line.match(/^.*==== Значение ====.*$/)) {
let definition_line = n + 1;
//После заголовка возможна пустая строка или помета (например, {{воен.}})
if (wiki[n+1].trim().length === 0
|| wiki[n+1].trim().match(/^{{[^}]*}}$/)) {
definition_line = n + 2;
}
definition = wiki[definition_line]
//# дефиниция
.replace(/^# ?/, "")
//[[1]]
.replace(/\[{2}([^\]|]*)\]{2}/g, "$1")
//[[1|2]]
.replace(/\[{2}[^|]*\|([^\]]*)\]{2}/g, "$1")
//{{сокр.|слово<!--ком.-->.*$
.replace(/\{{2}[а-яА-Я]+\.[^{}]*\|[^{}]*\}{2}\s*/g, "")
//~ : возможна вложенность
.replace(/\{{2}[а-яА-Я]+\.[^{}]*\|[^{}]*\}{2}\s*/g, "")
//{{-}}$
.replace(/\{\{-\}\}/g, "")
//{{помета|...}}$
.replace(/\{{2}помета\s*\|[^}]+\}{2}/g, "")
//{{действие|(глагол)#...lang=LC}}$
.replace(/\{{2}(действие)\s*\|([^#|]+)([#|].*lang=\w{2})?\}{2}/g, "$1 «$2»")
//{{пример/семантика|.*$ или {{пример/семантика}}
.replace(/\{{2}(пример|семантика)(\}{2}|\s*\|.*$)/g, "")
//{{1|слово<!--комментарий-->.*$
.replace(/\{{2}[^{}]*\|(lang=\w{2})?/g, "")
//{{1}}
.replace(/\{{2}([^\]|]*)\}{2}/g, "$1")
//'''ударение'''
.replace(/'''([^']*)'''/g, "«$1»")
//<!--комментарий-->
.replace(/<!--[^>]*-->/g, "")
//}}
.replace(/\}{2}/g, "")
//ссылки [n]
.replace(/\[[0-9]{1,}\]/g, "")
//^,; ...
.replace(/^\s*[,;]\s*/g, "")
//{{.*$
.replace(/\{{2}[^}]*$/g, "")
//HTML
.replace(/(<([^>]+)>)/ig, "")
//Неразрывный пробел
.replace(/&nbsp;/g, " ")
//Точка в конце предложения
.replace(/ ?$/,".");
return true;
}
});
//Разделение дефиниции на массив слов и знаков препинания и феминизация слов
var tokens = definition.match(/[\wа-яА-Яё]+|\d+| +|[.;,]|[^ \w\d\t.;,]+/ig) || [];
console.log(tokens);
//Замена местоимений, предлогов и проч.
HTML.full().innerHTML = FEM.words.convert(tokens.map(w => make_feminitives(w)[0]).join(""));
//DEBUG
console.log(definition);
console.log(tokens);
}
//Запрос значения слова в викисловаре
function get_wiktionary(term) {
var cors_url = "https://coors.now.sh/";
var wiki_url = cors_url + "https://ru.wiktionary.org/w/index.php?action=raw&title=" + term;
var xmlhttp = window.XMLHttpRequest
? new XMLHttpRequest()
: new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
parseWikiPage(xmlhttp.responseText);
}
};
xmlhttp.open("GET", wiki_url, true);
xmlhttp.send();
}
//Создание и вывод феминитива
function tr(word) {
//Исходное слово
var wd = word || HTML.input().value.trim().toLowerCase().replace(/<\/?[^>]+(>|$)/g, "").split(" ")[0];
var feminitives = "";
//Состояние по умолчанию
HTML.content().innerHTML = "Введите слово";
HTML.dict().innerHTML = "";
HTML.full().innerHTML = "";
HTML.vis(HTML.help(), "hidden");
HTML.vis(HTML.content(), "visible");
//Изменение адреса
URL.set(wd);
//Вывод информации
if (!wd) {
show_help();
return;
} else if (FEM.exceptions.contains(wd)) {
HTML.full().innerHTML = FEM.exceptions.definition(wd);
feminitives = FEM.exceptions.feminitives(wd);
} else {
get_wiktionary(wd);
feminitives = make_feminitives(wd);
}
//Вывод информации
HTML.input().value = wd;
HTML.content().innerHTML = feminitives[0].replace(/(.)/, s => s.toUpperCase());
HTML.dict().innerHTML = feminitives[1].join(" | ")
|| "Это слово и так прекрасно. Оставим его как есть.";
}
//------------------------------------------------------------------------------
//Параметры URL
var URL = {
opt: {},
description: {
clear: function() { this.text = "Как феминистки пишут разные слова."; },
set: function(wd) { this.text = 'Как феминистки пишут слово "' +wd+ '".'; },
},
set: function(wd) {
if (!wd) {
window.history.pushState({}, null, window.location.href.split('?')[0]);
this.description.clear();
} else {
window.history.pushState({}, null, window.location.href.split('?')[0]+'?word='+wd);
this.description.set(wd);
}
this.href = encodeURIComponent(window.location.href);
}
};
//Разбор параметров URL
URL.parse = function() {
var gy = window.location.search.substring(1).split("&");
gy.forEach(arg => {
let ft = arg.split("=");
this.opt[ft[0]] = this.opt[ft[0]] || decodeURIComponent(ft[1]);
});
URL.description.clear();
this.title = document.title;
this.opt.href = encodeURIComponent(window.location.href);
};
//Инициализация с разбором адресной строки
function init(container) {
HTML.init(container);
URL.parse();
if (URL.opt.word) {
HTML.input().value = URL.opt.word.replace(/\+/g," ");
tr();
} else {
show_help();
}
}

449
js/feminitives-rules.js

@ -0,0 +1,449 @@
//
// Copyright (C) 2016-2019, Maxim Lihachev, <envrm@yandex.ru>
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <https://www.gnu.org/licenses/>.
//
//------------------------------------------------------------------------------
var FEM = {};
//Слова для замены и исключения
//Имеют высший приоритет и не обрабатываются остальными правилами
FEM.words = {
'без' : 'без',
'как' : 'как',
'либо' : 'либо',
'например' : 'например',
'них' : 'них',
'под' : 'под',
'два' : 'две',
'весь' : 'вся',
'всё' : 'вся',
'чего' : 'чегой',
'ее' : 'е_е',
'её' : 'е_ё',
'кто' : 'котор_ая',
'каким' : 'как_ой',
'муж.' : 'жен.',
'муж' : 'жена',
'то' : 'т_а',
'того' : 'т_у',
'тот' : 'т_а',
'мужчина' : 'женщи_на',
'мужчины' : 'женщи_ны'
};
//Слова со специфичными определениями
FEM.exceptions = {
'феминист' : [ ['профеминист', 'союзник'],
"Мифическое создание, якобы поддерживающее феминизм. В реальности не встречается."
],
'жена' : [ ['мужерабка', 'подстилка патриархата'],
"Женщина, прогнувшаяся под патриархат и получающая удовольствие от угнетения."
]
};
// Формат:
// '<префикс>+окончание1|окончание2|...|окончаниеN' : {
// ['<шаблон>', <сколько удалять символов на конце слова>]
// }
//
// Окончания отсортированы от наиболее специфичных к наиболее общим
//
FEM.endings = {
//Исключения, которые не нужно феминизировать
'бо' : [
['либо', 2] // -либо
],
'их' : [
['их', 2] // нескольких
],
'ых' : [
['ых', 2] // грубых
],
'ной' : [
['ной', 3] // платёжной
],
'ных' : [
['ных', 3] // засушенных
],
'тей' : [
['тей', 3] // обязанностей
],
'ть' : [
['[аеи]ть', 2] // глаголы в инфинитиве
],
'ёт' : [
['[её]т', 2] // глаголы в форме 3 л. ед.ч.
],
'ют' : [
['ают', 2] // глаголы в форме мн.ч.
],
// имена прилагательные
'ая' : [
['[дкнш]ое', 2], // твёрдое, офицерское, полное, большое
['[дн]ый', 2], // твёрдый, полный
['[бвлмпт][оы][ей]', 2], // новый, круглый, знакомый, глупый, принятый
//['[бвклмнтш]ое', 2], // новое, сладкое, круглое, знакомое, полное, принятое, прошлое
['[шщ]ее', 2], // пешее, вещее
['[кнпщщ]ий', 2] // сладкий, дольний, глупый, пеший, пещий
],
'яя' : [
['[нчщ]ий', 2], // верхний, ползучий, знающий
['[нчщ]ее', 2] // верхнее, ползучее, знающее
],
'аяся' : [
['ееся', 4], // являющееся
['ийся', 4] // занимающийся
],
//
// ----- ФОРМА РОДИТЕЛЬНОГО ПАДЕЖА (преимущественно) -----
//
// форма мн.ч.
'ок|есс|ин|иц' : [
['вий', 2], // действий
['лей', 2], // родителей
['ств', 0], // свойств
['тра', 0], // метра
['еров', 2] // размеров
],
// форма ед.ч.
'ч+ки|ессы|ини|ицы' : [
['века', 2] // человека
],
'ки|ессы|ини|ицы' : [
['[ае]за', 1], // газа
['[ай]на', 1], // капитана, бассейна
['[ас]та', 1], // заката, роста
['[её]ма', 1], // водоёма
['[коя][тдя]а', 1], // отряда, объекта, города, живота
['[мн]ца', 2], // самца, солнца
['алла', 1], // металла
['дке', 2], // порядке
['е[жт]а', 1], // платежа, света
['зда', 1], // переезда
['ены', 1], // члены (организации)
['еста', 1], // теста
['и[дтщ]а', 1], // вида, кредита, туловища
['иала', 1], // материала
['инка', 1], // клинка
['кты', 1], // объекты
['лива', 1], // полива
['нта', 1], // варианта
['о[лрс]а', 1], // пола, надзора, космоса
['рева', 1], // дерева
['ства', 1], // государства
['те[лр][аия]', 1], // руководителя
['[оу]ви', 1], // крови, обуви
['фона', 1], // телефона
['я[дс]а', 1] // отряда, мяса
],
'ессы|ини|ицы' : [
// действия, равновесия, предприятия, метталургии
['[вгнст]и[ия]', 2],
['бега', 1], // побега
['[бк]оя', 1], // покоя, боя
['иги', 1], // подвиги
['[врт]ца', 1], // продавца, кварца, отца
['ени', 1], // времени
['есы', 1], // интересы
['[исы]ка', 1], // дворника, песка, языка
['изма', 1], // организма
['лия', 2], // изделия
['сьма', 1], // письма
['йма', 1], // займа
['нка', 1], // банка
['ья', 1], // несчастья
['уки', 1], // звуки
['юди', 1], // люди
['у[сх]а', 1] // вкуса, воздуха
],
'ии' : [
['[гн]и[ия]', 2] // металлургия
],
'есс|иц|инь' : [
['вых', 2] // паслёновых
],
'й+ки' : [
['боя', 1], // боя
['ви[йя]', 1] // действия
],
// имена прилагательные
'ей' : [
['[шщ]им', 2], // общим
['его', 3] // высшего
],
'ой' : [
// другого, молодого, женского, целого, художественного, которого, этого, большого
['[вгдклнртш]ого', 3],
['[ео]му', 3], // судебному
['[гд][иы]м', 2], // твёрдым, другим
['[клмнр][оы]м', 2] // музыкальном, прямым
],
//
// ----- ФОРМЫ ДАТЕЛЬНОГО И ПРЕДЛОЖНОГО ПАДЕЖА -----
//
// форма ед.ч.
'ке|ессе|ине|ице' : [
['[ия]де', 1], // виде, ряде
['[оя]ду', 1], // периоду, взгляду
['ане', 1], // плане
['е[нс]те', 1], // инструменте -> инструментессе, месте -> местессе
['[ар]те', 1], // результате, транспорте
['ессе', 1], // процессе
['[её]ме', 1], // объёме
['ксу', 1], // боксу -> боксессе
['лу', 1], // делу
['нию', 2], // отношению
['нке', 1], // ребёнке
['оду', 1], // период
['ету', 1], // предмету
['сту', 1], // росту
['усе', 1] // соусе
],
'ессе|ине|ице' : [
['еге', 1], // беге
['тве', 1], // государстве
['дне', 1], // судне -> суднессе
['[иы]ке', 1], // крике, языке
['нцу', 1], // концу -> концессе
['чае', 1] // случае
],
'ей|це' : [
['н[иь]ем', 2] // давлением -> давленией, вареньем -> вареньей
],
// форма мн.ч.
'ессам' : [
['кам', 2] // потомкам -> потомкессам
],
'ессам|иням|ицам' : [
['[дт]ям', 2] // людям, детям
],
//
// ----- ФОРМА ВИНИТЕЛЬНОГО ПАДЕЖА -----
//
'ую' : [
['шой', 2], // большой
['чий', 2], // горячий
['[вг]ое', 2] // готовое, другое
],
//
// ----- ФОРМА ТВОРИТЕЛЬНОГО ПАДЕЖА -----
//
'ессой|иней|ицей' : [
['[вгдл]ом', 2], // клювом, ремеслом, лозунгом, трудом
['ью', 2], // осенью
['[илнт][её]м', 2] // носителем, лезвием, остриём, временем, путём
],
'ками|ессами|ицами' : [
['[вдлн][ая]ми', 3], // островами, спортсменами, представителями, плодами
['[иы]ми', 3], // мелкими, продолговатыми
['тами', 3], // продуктами
['ьями', 4] // листьями
],
'ессами|ицами' : [
['[ая]ми', 3] // лицами, отношениями
],
// ---------------------------------
// ----- ИМЕНА СУЩЕСТВИТЕЛЬНЫЕ -----
// ---------------------------------
// Слова с заменой согласного основы
'ч+ка|есса|ина|иня|ица' : [
['ёнок', 1], // ребёнок
['ыка', 2], // владыка
['[ае]к', 1] // левак, человек
],
'ч+есса|ина|иня|ица' : [
['цо', 2] // лицо
],
'ц+есса|иня|ица' : [
['[бнр]ец', 2] // конец, творец, рубец
],
'к+иня' : [
['ст', 0], // специалист
['нт', 0] // агент
],
'н+ица' : [
['ль', 0] // создатель
],
'адья' : [
['поп', 0] // поп
],
'ка|есса|иня|ица' : [
// [а] прораб, нрав, раж, лаз, зал, кран, этап, нагар, ужас, закат, граф, врач, палаш, плащ
// [е] хлеб, лев, манеж, вырез, удел, овен, зацеп, характер, лес, авторитет, блеф, меч, флеш, клещ
// [ё] небоскрёб, рёв, ёж, -ёз, орёл, клён, поклёп, сапёр, овёс, зачёт, -ёф, -ёч, клёш, -ёщ
// [и] гриб, залив, чиж, бриз, спил, блин, хрип, жир, рис, визит, гриф, клич, мякиш, товарищ
// [н] -нб, -нв, -нж, ценз, -нл, джинн, -нп, жанр, анонс, бант, аканф, ленч, реванш, -нщ
// [о] сноб, ров, нож, воз, пол, район, клоп, узор, снос, азот, штоф, светоч, грош, овощ
// [р] ущерб, нерв, морж, -рз, жерл, сатурн, карп, -рр, барс, торт, торф, грач, фарш, борщ
// [y] сруб, обдув, уж, арбуз, гул, врун, закуп, амур, трус, жгут, пуф, луч, душ, хрущ
// [э] дзэн, кэб, дэв, -эж, -эз, -эл, нэп, мэр, аэс, поэт, -эф, -эч, -эш, -эщ
// [ю] книголюб, клюв, -юж, союз, -юл, вьюн, шлюп, бордюр, полюс, уют, -юф, ключ, плюш, плющ
['[аеёиноруэю][бвжзлнпрстфчшщ]', 0],
['[аеи][дн]ец', 2], // канадец, уроженец
['тец', 0], // отец
['[лн]ь', 1], // вождь, создатель, создателесса, камень
['л[блнпт]', 0], // металл, столб, челн, залп, болт
['льм', 0], // фильм
['мп', 0], // темп
['оша', 1], // юноша
['рин', 2], // татарин
['с[лст]', 0], // смысл, процесс, специалист
['ы[нсш]', 0], // сын, мыс, ландыш
['я[жнпрсчшщ]', 0] // пляж, кляп, маляр, пояс, мяч, гуляш, хрящ
],
'ка' : [
['яд',0], // отряд
['[аеёуы]м',0], // хам, джем, вотум, дым
['рий',0], // гербарий
['[аеоу]й',0], // бугай, лакей, зной, буй
['[рст]ь', 0] // фонарь, карась, гость
],
'есса|иня|ица' : [
// [а] маг, клад, знак, хам, страх, плац
// [е] берег, бред, человек, джем, цех, боец
// [ё] -ёг, лёд, отёк, -ёх, -ём, -ец
// [и] подвиг, вид, медик, грим, вывих, шприц
// [н] ринг, фонд, банк, сонм, бронх, принц
// [о] рог, сброд, срок, дом, вдох, -оц
// [р] торг, аккорд, кварк, шторм, стерх, кварц
// [с] пеласг, -сд, спуск, микрокосм, -сх, -сц
// [у] супруг, пуд, жук, вотум, пух, кибуц
// [ы] припрыг, стыд, клык, дым, жмых, -ыц
// [я] стяг, отряд, тюфяк, -ям, лях, -паяц
['[аеёинорсуыя][гдкмхц]', 0],
['[аеи]лец', 2], // жилец
['[бвдт]р', 0], // бобр, кентавр, театр, кадр
['з[дм]', 0], // съезд
['ол[гк]', 0], // долг, полк
['офе', 1], // кофе
['ыв', 0], // взрыв
['[аеиоу]й',1], // бугай, лакей, гербарий, зной, буй
['[дрст]ь', 1], // вождь, фонарь, карась, путь
['ядя', 1], // дядя
['дья', 2], // судья
['[кы]т', 0], // реликт, опыт
['к[сх]', 1], // бокс, сикх
// ----- слова среднего рода -----
// небо, существо, чудо, яблоко, стекло, письмо, окно, ведро, колесо, пальто, ухо, плечо
['[бвдклмнрстхч]о', 1],
// действие, оружие, приспособление, кушанье, участие, отличие, жильё, согласие
['[вжлнстч][иь][её]', 2],
['мя', 1], // время
['[лрцщ]е', 1] // поле, море, солнце, вместилище
],
'есса' : [
['[длн]ие', 1] // правосудие, изделие, мнение
],
'ыня' : [
['рин', 2], // барин
['уз', 0] // арбуз
],
'ица' : [
['[дл]ие', 2], // правосудие, изделие
['ще', 3] // вместилище
],
'ша' : [
['у[нт]', 0], // врун, лилипут
['ир', 0] // командир
],
'ь+я' : [
['ун', 0] // врун
],
// формы мн.ч.
'ессы|ыни|ицы' : [
['нга', 1], // ранга
['о[дс]ы', 1], // выводы, матросы
['усы', 2] // вкусы
],
// ----- РАЗНОЕ -----
'инь' : [
['дей', 2] //людей -> людинь
],
'на' : [
['обно', 2] //способно -> способна
]
};
//Случайный элемент списка
FEM.random_word = wordlist => wordlist[Math.floor(Math.random() * wordlist.length)];
//Проверка на исключение
FEM.exceptions.contains = word => Object.keys(FEM.exceptions).includes(word);
//Список значений
FEM.exceptions.feminitives = word => [FEM.random_word(FEM.exceptions[word][0]), FEM.exceptions[word][0]];
//Дефиниция слова-исключения
FEM.exceptions.definition = word => FEM.exceptions[word][1];

497
js/feminitives.js

@ -1,497 +0,0 @@
// Copyright (C) 2016-2017, Maxim Lihachev, <envrm@yandex.ru>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// [ ] TODO: валидация
//------------------------------------------------------------------------------
'use strict';
//------------------------------------------------------------------------------
//Иерархия элементов на странице
var HTML = {
container: "",
_select: function(element) { return document.getElementById(this.container + "-" + element); },
input: function() { return this._select("word"); },
button: function() { return this._select("convert"); },
dict: function() { return this._select("dict"); },
content: function() { return this._select("content"); },
full: function() { return this._select("full"); },
help: function() { return this._select("help"); },
image: function() { return this._select("image"); },
};
//Вывод справки с примерами использования
function show_help() {
HTML.vis(HTML.help());
HTML.vis(HTML.content());
}
//Смена названия по клику
function swap_title(id) {
var e = document.getElementById(id);
if(e.style.display == 'inline') {
e.style.display = 'none';
} else {
e.style.display = 'inline';
}
}
HTML.vis = function(e, v) {
if (v !== undefined) {
e.style.visibility = v;
} else {
e.style.visibility = e.style.visibility === "visible" ? "hidden" : "visible";
}
}
//Инициализация документа
HTML.init = function(root) {
//Задание базового id для всех элементов
this.container = root;
//Конвертирование по нажатию <Enter>
this.input().addEventListener('keyup', event => {
event.preventDefault();
event.keyCode == 13 && tr();
});
//Конвертирование по нажатию кнопки
this.button().onclick = () => tr();
};
//------------------------------------------------------------------------------
//Правила создания феминитивов
var FEM = {};
FEM.endings = {
'ка' : [
['[аеёо]р', 0],
['[её]т', 0], //авторитет -> авторитетка
['а[ншб]', 0], //кран -> кранка, краб -> крабка
['ец', 2], //канадец -> канадка
['и[лр]', 0], //библиофил -> библиофилка, командир -> командирка
['ин', 2], //татарин -> татарка
['ль', 1], //создатель -> создателка
['о[тн]', 0], //гот -> готка, адрон -> адронка
['рг', 1],
['[ус]т', 0], //специалист -> специалистка
['у[нйп]', 0] //колдун -> колдунка
],
'чка' : [
['[ае]к', 1] //левак -> левачка, человек -> человечка
],
'ина' : [
['ас', 0],
['уй', 1], //буй -> буина
['уд', 0], //сосуд -> сосудина
['ил', 0] //библиофил -> библиофилина
],
'иха' : [
['[аеёов]р', 0], //автор -> авториха
['а[чб]', 0], //врач -> врачиха, краб -> крабиха
['ец', 2], //канадец -> канадиха
['и[лр]', 0], //библиофил -> библиофилиха, командир -> командириха
['ль', 1], //создатель -> создателиха
['рк', 0], //кварк -> кваркиха
['о[гдтнп]', 0], //гот -> готиха, адрон -> адрониха, биолог -> биологиха, метод -> методиха, клоп -> клопиха
['у[дпт]', 0], //труп -> трупиха, сосуд -> сосудиха
['уй', 1] //буй -> буиха
],
'иня' : [
['[аеёов]р', 0],
['[её]т', 2], //авторитет -> авторитиня
['[оиы]к', 0], //язык -> языкиня
['а[вбкфч]', 0], //левак -> левакиня, граф -> графиня, врач -> врачиня, краб -> крабиня, состав -> составиня
['во', 1], //существо -> существиня
['ек', 0], //человек -> человекиня
['ец', 2], //канадец -> канадиня
['ил', 0], //библиофил -> библиофилиня
['ль', 1], //создатель -> создателиня
['о[дг]', 0], //биолог -> биологиня
['од', 0], //метод -> методиня
['р[гк]', 0], //кварк -> кваркиня
['ро', 1], //ведро -> ведриня
['со', 1], //колесо -> колесиня
['сс', 0], //процесс -> процессиня
['[кс]т', 0], //специалист -> специалистиня, объект -> объектиня
['уй', 1], //буй -> буиня
['у[тпх]', 0] //труп -> трупиня
],
'ыня' : [
['ин', 2], // боярин -> боярыня
],
'киня' : [
['[аеёо]р', 0],
['ок', 0],
['ст', 0], //специалист -> специалисткиня
['ан', 0],
['ил', 0], //библиофил -> библиофилкиня
['уй', 0] //буй -> буйкиня
],
'есса' : [
['[аеёов]р', 0],
['[её]т', 2], //авторитет -> авторитесса
['[лн]ь', 1], //создатель -> создателесса, камень -> каменесса
['[оиы]к', 0], //язык -> языкесса
['[оэ]т', 0], //гот -> готесса, поэт -> поэтесса
['а[вчнб]', 0], //врач -> врачесса, баран -> баранесса, краб -> крабесса, состав -> составесса
['во', 1], //существо -> существесса
['е[кнц]', 0], //член -> членесса, канадец -> канадесса, человек -> человекесса
['и[лр]', 0], //библиофил -> библиофилесса, командир -> командиресса
['[лр]о', 1], //тело -> телесса, ведро -> ведресса
['о[ндгп]', 0], //метод -> методесса, адрон -> адронесса, биолог -> биологесса, клоп -> клопесса
['р[гк]', 0], //кварк -> кваркесса
['ст', 0], //специалист -> специалистесса
['у[дпнхт]', 0], //сосуд -> сосудесса, колдун -> колдунесса, олух -> олухесса
['уй', 1], //буй -> буесса
['ще', 0], //вместилище -> вместилищесса
['ый', 2], //учёный -> учёнесса
['яд', 0] //взгляд -> взглядесса
],
'ица' : [
['[аеёов]р', 0],
['[её]т', 2], //авторитет -> авторитица
['а[вбнсч]', 0], //врач -> врачица, краб -> крабица, состав -> составица
['во', 1], //существо -> существица
['ен', 0], //член -> членица
['ец', 2], //канадец -> канадица
['ик', 2],
['и[влр]', 0], //библиофил -> библиофилица, командир -> командирица
['нь', 1], //камень -> каменица
['о[гд]', 0], //биолог -> биологиня, метод -> методица
['рг', 0],
['ст', 3], //специалист -> специалица
['сс', 0], //процесс -> процессица
['у[днпчт]', 0], //сосуд -> сосудица, колдун -> колдуница, труп -> трупица
['уй', 1], //буй -> буица
['ще', 3], //вместилище -> вместилищесса
['яд', 0] //взгляд -> взглядица
],
'ница' : [
['ль', 0], //создатель -> создательница
['ас', 0],
['[её]т', 0], //авторитет -> авторитетица
['ец', 2], //канадец -> канадница
['уй', 0] //буй -> буйница
],
'ая' : [
['[ыио]й', 2], //учёный -> учёная, знающий -> знающая
['ое', 2]
],
'ша' : [
['[её]т', 1], //вертолёт -> вертолёша
['ут', 1], //лилипут -> лилипутша
['ир', 0] //командир -> командирша
],
'адья' : [
['оп', 0] // поп -> попадья
],
//----- ДАЛЬШЕ ИДЁТ ШИЗА -----
'ии' : [
['и[ия]', 2], //металлургии -> металлург_ии, произведения -> произведении
],
'ца' : [
['ие', 1], //металлургии -> металлург_ии, произведения -> произведении
],
'ми' : [
['ми', 2] //знаниями -> знания_ми
],
'ой' : [
['го', 3] //художественного -> художественн_ой
],
'инь' : [
['ей', 2] //людей -> люд_ей
],
'ти' : [
['ти', 2] //области -> облас_ти
],
'ю' : [
['ью', 1] //матерью -> матерь_ю
],
'ны' : [
['на', 2] //бассейна -> бассей_ны
],
'на' : [
['но', 2] //способно -> способна
],
'ки' : [
['ца', 2] //самца -> самки
],
'аяся' : [
['ся', 4], //занимающийся -> занимающ_аяся
],
};
//Слова со специфичными определениями
FEM.exceptions = {
'феминист' : [ ['профеминист', 'союзник'],
"Мифическое создание, якобы поддерживающее феминизм. В реальности не встречается."
],
'жена' : [ ['мужерабка', 'подстилка патриархата'],
"Женщина, прогнувшаяся под патриархат и получающая удовольствие от угнетения."
]
};
//Проверка на исключение
FEM.exceptions.contains = function(word) {
return Object.keys(this).includes(word);
};
//Список значений
FEM.exceptions.feminitives = function(word) {
return [random_word(this[word][0]), this[word][0]];
};
//Дефиниция слова-исключения
FEM.exceptions.definition = function(word) {
return this[word][1];
};
//Слова для замены
FEM.words = {
'то' : 'т_а',
'тот' : 'т_а',
'того' : 'т_у',
'кто' : 'котор_ая',
'её' : 'е_ё',
'ее' : 'е_е',
'ий' : 'ая',
'человек' : 'человека',
'муж' : 'жен'
};
FEM.words.convert = function(string) {
for (var fem_w in this) {
string = string.replace(new RegExp('(^|\\s)+' + fem_w, "ig"), '$1' + this[fem_w])
.replace(/(.)/, s => s.toUpperCase());
}
return string;
};
//------------------------------------------------------------------------------
//Первый элемент списка - окончание (в виде регулярного выражения)
let ending = tuple => new RegExp("^.*" + tuple[0] + "$", "i");
//Второй элемент списка - смещение
let offset = tuple => tuple[1];
//Случайный элемент списка
let random_word = wordlist => wordlist[Math.floor(Math.random() * wordlist.length)];
//Оборачивание в <span> с указанным классом
let html_wrap = (str, cl) => `<span class="${cl}">${str}</span>`;
//Цветовое выделение текста
let css_end = ending => html_wrap(ending, "ending");
//Символ gender gap
let css_gender_gap = html_wrap(' \u26A7 ', "queer");
//------------------------------------------------------------------------------
//Конструирование феминитива с gender_gap
function construct_feminitive(stem, ending, gap) {
return gap ? stem + css_gender_gap + css_end(ending) : stem + "_" + ending;
}
//Отправка адреса страницы в vk.com
function share_page() {
let vk_url = "http://vk.com/share.php"
+ "?url=" + URL.href
+ "&title=" + URL.title
+ "&description=" + URL.description.text;
let new_tab = window.open(vk_url,'_blank');
new_tab.focus();
}
//Сохранение изображения с феминитивом
function download_image() {
html2canvas(HTML.image(), {
onrendered: canvas => {
let a = document.createElement('a');
a.href = canvas.toDataURL();
a.download = HTML.content().innerHTML + '.png';
a.click();
}
});
}
//Создание феминитива
function make_feminitives(word) {
//Обрабатываем только слова длиннее трёх символов
if (word.length < 3) return [word, word];
var stem = ""; //Основа слова
var current_ending = word.slice(-2); //Текущее окончание
var feminitives = []; //Массив феминитивов
var femicards = []; //Массив феминитивов для карточки
for (let fem_ending in FEM.endings) {
FEM.endings[fem_ending].forEach(end => {
if (ending(end).test(current_ending)) {
//Удаление лишних букв из основы
stem = offset(end) === 0 ? word : word.slice(0, -offset(end));
//Добавление фем-варианта слова в массив
feminitives.push(construct_feminitive(stem, fem_ending, 1));
femicards.push(construct_feminitive(stem, fem_ending, 0));
}
});
}
//При отсутствии феминитивов считать корректным исходное слово
return [random_word(femicards) || word, feminitives];
}
//Поиск и феминизация дефиниции в викистранице
function parseWikiPage(page) {
var wiki = page.split('\n');
var definition = "";
wiki.some((line, n) => {
if (line.match(/^.*==== Значение ====.*$/)) {
console.log(wiki[n+1]); //DEBUG
definition = wiki[n+1]
.replace(/^# ?/, "") //# дефиниция
.replace(/\[{2}([^\]\|]*)\]{2}/g, "$1") //[[1]]
.replace(/\[{2}[^\|]*\|([^\]]*)\]{2}/g, "$1") //[[1|2]]
.replace(/\[{2}([^\]\|]*)\}{2}/g, "$1") //{{1}}
.replace(/\{{2}[^\{\}]*\}{2} ?/g, "") //{{1|2}}
.replace(/\{{2}[^\{\}]*\|.*/g, "") //{{1|слово<!--комментарий-->.*$
.replace(/\{{2}[^\{\}]*\}{2} ?/g, "") //~ : возможна вложенность
.replace(/\[[0-9]{1,}\]/g, "") //ссылки [n]
.replace(/^ *, */g, "") //^, ...
.replace(/ ?$/,"."); //Точка в конце предложения
return true;
}
});
//Разделение дефиниции на массив слов и знаков препинания и феминизация слов
var tokens = definition.match(/[\wа-яА-Яё]+|\d+| +|[.;,]|[^ \w\d\t.;,]+/ig) || [];
console.log(tokens);
//Замена местоимений, предлогов и проч.
HTML.full().innerHTML = FEM.words.convert(tokens.map(w => make_feminitives(w)[0]).join(""));
//DEBUG
console.log(definition);
console.log(tokens);
}
//Запрос значения слова в викисловаре
function get_wiktionary(term) {
var cors_url = "https://coors.now.sh/";
var wiki_url = cors_url + "https://ru.wiktionary.org/w/index.php?action=raw&title=" + term;
var xmlhttp = window.XMLHttpRequest
? new XMLHttpRequest()
: new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
parseWikiPage(xmlhttp.responseText);
}
};
xmlhttp.open("GET", wiki_url, true);
xmlhttp.send();
}
//Создание и вывод феминитива
function tr(word) {
//Исходное слово
var wd = word || HTML.input().value.trim().toLowerCase().replace(/<\/?[^>]+(>|$)/g, "").split(" ")[0];
var feminitives = "";
//Состояние по умолчанию
HTML.content().innerHTML = "Введите слово";
HTML.dict().innerHTML = "";
HTML.full().innerHTML = "";
HTML.vis(HTML.help(), "hidden");
HTML.vis(HTML.content(), "visible");
//Изменение адреса
URL.set(wd);
//Вывод информации
if (!wd) {
show_help();
return;
} else if (FEM.exceptions.contains(wd)) {
HTML.full().innerHTML = FEM.exceptions.definition(wd);
feminitives = FEM.exceptions.feminitives(wd);
} else {
get_wiktionary(wd);
feminitives = make_feminitives(wd);
}
//Вывод информации
HTML.input().value = wd;
HTML.content().innerHTML = feminitives[0].replace(/(.)/, s => s.toUpperCase());
HTML.dict().innerHTML = feminitives[1].join(" | ")
|| "Это слово и так прекрасно. Оставим его как есть.";
}
//------------------------------------------------------------------------------
//Параметры URL
var URL = {
opt: {},
description: {
clear: function() { this.text = "Как феминистки пишут разные слова."; },
set: function(wd) { this.text = 'Как феминистки пишут слово "' +wd+ '".'; },
},
set: function(wd) {
if (!wd) {
window.history.pushState({}, null, window.location.href.split('?')[0]);
this.description.clear();
} else {
window.history.pushState({}, null, window.location.href.split('?')[0]+'?word='+wd);
this.description.set(wd);
}
this.href = encodeURIComponent(window.location.href);
}
};
//Разбор параметров URL
URL.parse = function() {
var gy = window.location.search.substring(1).split("&");
gy.forEach(arg => {
let ft = arg.split("=");
this.opt[ft[0]] = this.opt[ft[0]] || decodeURIComponent(ft[1]);
});
URL.description.clear();
this.title = document.title;
this.opt.href = encodeURIComponent(window.location.href);
};
//Инициализация с разбором адресной строки
function init(container) {
HTML.init(container);
URL.parse();
if (URL.opt.word) {
HTML.input().value = URL.opt.word.replace(/\+/g," ");
tr();
} else {
show_help();
}
}

0
js/html2canvas.js

Loading…
Cancel
Save