最終更新 2 weeks ago

"Микросервис для расстановки ударений в русском тексте. Выделите букву и нажмите Ctrl+Q.

修正履歴 20d48b13fd5b7be419891a72d77d000ffaca168b

accent_marker.html Raw
1<!DOCTYPE html>
2<html lang="ru">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>Расстановка ударений</title>
7 <meta name="description" content="Микросервис для расстановки ударений в русском тексте. Выделите букву и нажмите Ctrl+Q.">
8 <meta name="keywords" content="ударения, русский язык, текст, форматирование, ударные гласные">
9 <meta name="author" content="ООО Психотроника">
10 <meta name="copyright" content="ООО Психотроника, 2026">
11 <meta name="robots" content="index, follow">
12 <style>
13 * {
14 margin: 0;
15 padding: 0;
16 box-sizing: border-box;
17 }
18
19 body {
20 font-family: Arial, sans-serif;
21 line-height: 1.6;
22 padding: 20px;
23 background-color: #f5f5f5;
24 }
25
26 .container {
27 max-width: 800px;
28 margin: 0 auto;
29 background: white;
30 padding: 20px;
31 border-radius: 8px;
32 box-shadow: 0 2px 10px rgba(0,0,0,0.1);
33 }
34
35 h1 {
36 color: #333;
37 margin-bottom: 10px;
38 text-align: center;
39 }
40
41 .description {
42 color: #666;
43 margin-bottom: 20px;
44 text-align: center;
45 font-size: 14px;
46 }
47
48 textarea {
49 width: 100%;
50 min-height: 300px;
51 padding: 15px;
52 font-size: 16px;
53 line-height: 1.5;
54 border: 2px solid #ddd;
55 border-radius: 4px;
56 resize: vertical;
57 font-family: inherit;
58 margin-bottom: 15px;
59 }
60
61 textarea:focus {
62 outline: none;
63 border-color: #4CAF50;
64 }
65
66 .controls {
67 display: flex;
68 justify-content: space-between;
69 align-items: center;
70 margin-bottom: 20px;
71 padding: 15px;
72 background: #f8f9fa;
73 border-radius: 4px;
74 }
75
76 .hotkey-info {
77 font-size: 14px;
78 color: #666;
79 }
80
81 .hotkey-info kbd {
82 background: #e9ecef;
83 padding: 2px 6px;
84 border-radius: 3px;
85 border: 1px solid #ced4da;
86 font-family: monospace;
87 }
88
89 .examples {
90 background: #f8f9fa;
91 padding: 15px;
92 border-radius: 4px;
93 margin-top: 20px;
94 font-size: 14px;
95 }
96
97 .examples h3 {
98 margin-bottom: 10px;
99 color: #333;
100 }
101
102 .example-item {
103 margin-bottom: 5px;
104 color: #666;
105 }
106
107 .copyright {
108 text-align: center;
109 margin-top: 20px;
110 padding: 10px;
111 color: #666;
112 font-size: 12px;
113 border-top: 1px solid #eee;
114 }
115
116 footer {
117 text-align: center;
118 margin-top: 20px;
119 color: #888;
120 font-size: 12px;
121 }
122 </style>
123</head>
124<body>
125 <div class="container">
126 <h1>Добавление ударений в текст</h1>
127 <div class="description">
128 Выделите букву и нажмите Ctrl+Q (Cmd+Q на Mac), чтобы добавить ударение
129 </div>
130
131 <div class="controls">
132 <div class="hotkey-info">
133 Горячая клавиша: <kbd>Ctrl</kbd> + <kbd>Q</kbd> (Windows/Linux) или <kbd>Cmd</kbd> + <kbd>Q</kbd> (Mac)
134 </div>
135 </div>
136
137 <textarea id="textInput" placeholder="Введите или вставьте ваш текст здесь..."></textarea>
138
139 <div class="examples">
140 <h3>Примеры замены:</h3>
141 <div class="example-item">а → á (если это ударная "а")</div>
142 <div class="example-item">о → ó (если это ударная "о")</div>
143 <div class="example-item">у → у́ (во всех остальных случаях знак ударения ставится после буквы)</div>
144 <div class="example-item">Выделите одну букву и нажмите Ctrl+Q</div>
145 </div>
146 </div>
147
148 <footer>
149 Микросервис для расстановки ударений
150 <div class="copyright">
151 &copy; ООО Психотроника, 2026.
152 </div>
153
154 </footer>
155
156 <script>
157
158// Правила замены для ударных гласных
159const stressRules = {
160 'а': 'á',
161 'о': 'ó',
162 'е': 'é',
163 'у': 'у́',
164 'ы': 'ы́',
165 'э': 'э́',
166 'ю': 'ю́',
167 'я': 'я́',
168 'и': 'и́',
169 'А': 'Á',
170 'О': 'Ó',
171 'Е': 'É',
172 'У': 'У́',
173 'Ы': 'Ы́',
174 'Э': 'Э́',
175 'Ю': 'Ю́',
176 'Я': 'Я́',
177 'И': 'И́'
178};
179
180// Обратная замена для удаления ударений
181const reverseStressRules = {
182 'á': 'а', 'Á': 'А',
183 'ó': 'о', 'Ó': 'О',
184 'é': 'е', 'É': 'Е',
185 'у́': 'у', 'У́': 'У',
186 'ы́': 'ы', 'Ы́': 'Ы',
187 'э́': 'э', 'Э́': 'Э',
188 'ю́': 'ю', 'Ю́': 'Ю',
189 'я́': 'я', 'Я́': 'Я',
190 'и́': 'и', 'И́': 'И'
191};
192
193// Получаем текстовое поле
194const textInput = document.getElementById('textInput');
195
196// Функция для проверки, заканчивается ли текст на ударение
197function endsWithStress(text) {
198 // Проверяем последний символ на наличие ударения (комбинирующий символ ́)
199 if (text.length === 0) return false;
200
201 // Если последний символ - комбинирующее ударение (U+0301)
202 if (text.charCodeAt(text.length - 1) === 0x0301) {
203 return true;
204 }
205
206 // Проверяем комбинированные символы (ударение как часть символа)
207 const lastChar = text.charAt(text.length - 1);
208 return reverseStressRules.hasOwnProperty(lastChar);
209}
210
211// Функция для удаления ударения
212function removeStress(text) {
213 if (text.length === 0) return text;
214
215 // Если последний символ - комбинирующее ударение
216 if (text.charCodeAt(text.length - 1) === 0x0301) {
217 return text.slice(0, -1);
218 }
219
220 // Если последний символ имеет предварительно составленное ударение
221 const lastChar = text.charAt(text.length - 1);
222 if (reverseStressRules[lastChar]) {
223 return text.slice(0, -1) + reverseStressRules[lastChar];
224 }
225
226 return text;
227}
228
229// Обработка нажатия клавиш
230textInput.addEventListener('keydown', function(e) {
231 // Проверяем комбинацию Ctrl+Q/Й или Cmd+Q/Й
232 if ((e.ctrlKey || e.metaKey) && (e.key === 'q' || e.key === 'й' || e.key === 'Й' || e.key === 'Q')) {
233 e.preventDefault();
234
235 const start = this.selectionStart;
236 const end = this.selectionEnd;
237
238 // Если нет выделения или выделен 0 символов
239 if (start === end) {
240 alert('Пожалуйста, выделите хотя бы одну букву');
241 return;
242 }
243
244 const selectedText = this.value.substring(start, end);
245
246 // Проверяем, что есть хотя бы одна русская буква в выделении
247 if (!/[а-яА-ЯёЁ]/.test(selectedText)) {
248 alert('Выделите хотя бы одну русскую букву');
249 return;
250 }
251
252 // ПРОВЕРКА: если текст заканчивается на ударение - удаляем его
253 if (endsWithStress(selectedText)) {
254 const textWithoutStress = removeStress(selectedText);
255 const newText = this.value.substring(0, start) + textWithoutStress + this.value.substring(end);
256 this.value = newText;
257 this.selectionStart = start + textWithoutStress.length;
258 this.selectionEnd = start + textWithoutStress.length;
259 }
260 // ДОБАВЛЕНИЕ ударения
261 else {
262 // Если выделена одна буква - применяем правила замены
263 if (selectedText.length === 1) {
264 let replacement;
265 if (stressRules[selectedText]) {
266 replacement = stressRules[selectedText];
267 } else {
268 replacement = selectedText + '́';
269 }
270
271 // Заменяем выделенный текст
272 const newText = this.value.substring(0, start) + replacement + this.value.substring(end);
273 this.value = newText;
274 this.selectionStart = start + replacement.length;
275 this.selectionEnd = start + replacement.length;
276 }
277 // Если выделено несколько символов - ставим ударение после выделения
278 else {
279 const replacement = selectedText + '́';
280 const newText = this.value.substring(0, start) + replacement + this.value.substring(end);
281 this.value = newText;
282 this.selectionStart = start + replacement.length;
283 this.selectionEnd = start + replacement.length;
284 }
285 }
286
287 this.focus();
288 }
289});
290
291// Фокус на текстовом поле при загрузке
292window.addEventListener('load', function() {
293 textInput.focus();
294});
295
296 </script>
297</body>
298</html>
299