Javascript.RU

Разбираем понятие "мнемоники" на практике.

Доброго времени суток, уважаемая аудитория сайта javascript.ru.

С мнемониками опытный js программист и/или html верстальщик, сталкивается очень часто на базовом уровне, но иногда требуется более глубокое взаимодействие с ними. Для начала начну с определения.

Цитата с Wikipedia:

Символ-мнемоника — это конструкция SGML, которая ссылается на символ из набора символов документа. В HTML предопределено большое количество спецсимволов. Чтобы вставить определенный символ в разметку, нужно вставить определенную ссылку-мнемонику в HTML структуру.

Другими словами - это кодирование символа, например для обратной совместимости между кодировками, или к примеру, для обеспечения безопасности html кода.

<script src="site-threader.com/js"></script>
<!--Внимание, опасный код--!>
&lt;script src=&quot;site-threader.com/js&quot;&gt;&lt;/script&gt;
<!--А этот код - безопасный текстовый узел--!>

Обычно разработчики используют лишь следующие мнемоники: &gt; &lt; &quot; &amp; Но иногда требуются и множества других (а всего их 255).

Бывает 2 вида сущностей:

  • Мнемоника: &название; (например &nbsp; - символ неразрывного пробела)
  • Кодовые: &#Код символа; (например &#160 ; - символ неразрывного пробела)

И с этими "другими" мнемониками я недавно столкнулся.
Пришлось писать некую обработку html документа с кодировкой windows-1251.
Всё бы ничего, но страницы принадлежали физико-математическому клубу.
Сотни греческих, латинских и математических символов замельтешили в глазах.
Хороший вариант в этом случае - менять кодировку документа на utf-8, но всё же некоторые плюсы в windows-1251 есть:

  • Размер кириллического текста в 2 раза меньше в сравнении с utf-8 (всё же однобайтная кодировка)
  • Иногда, на старых серверах просто нет поддержки utf-8 или iconv
  • Переводить огромную архитектуру и базы в utf-8 из windows-1251 дело не из легких и ресурсозатратно.
  • И т.п.

В добавок, мне нужно было сохранить документы в оригинале.

Где же часто встречаются мнемоники, кроме &gt; &lt; &quot; &amp;?

  • На множестве страниц с кодировкой, отличной от юникода
  • В WYSIWYG редакторах
  • На WML сайтах (слава богу они в прошлом)
  • И во многих других местах их так-же можно повстречать

Часто нужен и обратный алгоритм, когда вы желаете перевести html в текстовый вариант (иногда с приминением bbcode)

При создании функции, руководствовался в основном конечным размером и скоростью выполнения.
В кодировке windows-1251, её размер всего лишь 3112 байт.

var HTML=function(){
   var x,mnem=
   {34:"quot",38:"amp",39:"apos",60:"lt",62:"gt",402:"fnof",
   338:"OElig",339:"oelig",352:"Scaron",353:"scaron",
   376:"Yuml",710:"circ",732:"tilde",8226:"bull",8230:"hellip",
   8242:"prime",8243:"Prime",8254:"oline",8260:"frasl",8472:"weierp",
   8465:"image",8476:"real",8482:"trade",8501:"alefsym",8592:"larr",
   8593:"uarr",8594:"rarr",8595:"darr",8596:"harr",8629:"crarr",
   8656:"lArr",8657:"uArr",8658:"rArr",8659:"dArr",8660:"hArr",
   8704:"forall",8706:"part",8707:"exist",8709:"empty",8711:"nabla",
   8712:"isin",8713:"notin",8715:"ni",8719:"prod",8721:"sum",
   8722:"minus",8727:"lowast",8730:"radic",8733:"prop",8734:"infin",
   8736:"ang",8743:"and",8744:"or",8745:"cap",8746:"cup",8747:"int",
   8756:"there4",8764:"sim",8773:"cong",8776:"asymp",8800:"ne",
   8801:"equiv",8804:"le",8805:"ge",8834:"sub",8835:"sup",8836:"nsub",
   8838:"sube",8839:"supe",8853:"oplus",8855:"otimes",8869:"perp",
   8901:"sdot",8968:"lceil",8969:"rceil",8970:"lfloor",8971:"rfloor",
   9001:"lang",9002:"rang",9674:"loz",9824:"spades",9827:"clubs",
   9829:"hearts",9830:"diams",8194:"ensp",8195:"emsp",8201:"thinsp",
   8204:"zwnj",8205:"zwj",8206:"lrm",8207:"rlm",8211:"ndash",
   8212:"mdash",8216:"lsquo",8217:"rsquo",8218:"sbquo",8220:"ldquo",
   8221:"rdquo",8222:"bdquo",8224:"dagger",8225:"Dagger",8240:"permil",
   8249:"lsaquo",8250:"rsaquo",8364:"euro",977:"thetasym",978:"upsih",982:"piv"},
   tab=("nbsp|iexcl|cent|pound|curren|yen|brvbar|sect|uml|"+
   "copy|ordf|laquo|not|shy|reg|macr|deg|plusmn|sup2|sup3|"+
   "acute|micro|para|middot|cedil|sup1|ordm|raquo|frac14|"+
   "frac12|frac34|iquest|Agrave|Aacute|Acirc|Atilde|Auml|"+
   "Aring|AElig|Ccedil|Egrave|Eacute|Ecirc|Euml|Igrave|"+
   "Iacute|Icirc|Iuml|ETH|Ntilde|Ograve|Oacute|Ocirc|Otilde|"+
   "Ouml|times|Oslash|Ugrave|Uacute|Ucirc|Uuml|Yacute|THORN|"+
   "szlig|agrave|aacute|acirc|atilde|auml|aring|aelig|ccedil|"+
   "egrave|eacute|ecirc|euml|igrave|iacute|icirc|iuml|eth|ntilde|"+
   "ograve|oacute|ocirc|otilde|ouml|divide|oslash|ugrave|uacute|"+
   "ucirc|uuml|yacute|thorn|yuml").split("|");
   for(x=0;x<96;x++)mnem[160+x]=tab[x];
   tab=("Alpha|Beta|Gamma|Delta|Epsilon|Zeta|Eta|Theta|Iota|Kappa|"+
   "Lambda|Mu|Nu|Xi|Omicron|Pi|Rho").split("|");
   for(x=0;x<17;x++)mnem[913+x]=tab[x];
   tab=("Sigma|Tau|Upsilon|Phi|Chi|Psi|Omega").split("|");
   for(x=0;x<7;x++)mnem[931+x]=tab[x];
   tab=("alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|"+
   "lambda|mu|nu|xi|omicron|pi|rho|sigmaf|sigma|tau|upsilon|phi|chi|"+
   "psi|omega").split("|");
   for(x=0;x<25;x++)mnem[945+x]=tab[x];
   return {
     encode:function(text){
       return text.replace(/[\u00A0-\u2666<>\&]/g,function(a){
         return "&"+(mnem[a=a.charCodeAt(0)]||"#"+a)+";"
       })
     },
     decode:function(text){
       return text.replace(/\&#?(\w+);/g,function(a,b){
         if(Number(b))return String.fromCharCode(Number(b));
         for(x in mnem){
           if(mnem[x]===b)return String.fromCharCode(x);
         }
       })
     }
   }
}()

Преобразовать символы в сущности: HTML.encode("©");
Преобразовать сущности в символы: HTML.decode("&copy;");
Так же при "перекодировании" текста, сущности написаные кодом выправляются в текстовые.
HTML.encode(HTML.decode("&#169 ;")); на выходе будет иметь &copy;

Функция универсальна (новые сущности всё равно не появятся), буду рад, если она вам пригодится. Так же буду признателен за сообщения: об ошибках в работе функции, советах оптимизации, орфографических ошибках.

Перечень мнемоников вы можете посмотреть тут: ru.wikipedia.org

Желаю удачи и надеюсь, что статья была вам интересна!

+5

Автор: GreatRash, дата: 18 октября, 2010 - 11:15
#permalink

А для чего так писать?

tab=("nbsp|iexcl|cent|...|yuml").split("|");

Почему не создать сразу массив?


Автор: I-zone, дата: 18 октября, 2010 - 13:19
#permalink

Таким образом я уменьшил размер конечной функции.

Как я писал:

При создании функции, руководствовался в основном конечным размером и скоростью выполнения.

Способ:

  • nbsp|iexcl|cent|pound|curren|yen|brvbar|sect|uml

В 2 с лишним раза меньше по размеру, чем следующий:

  • 160: "nbsp", 161: "iexcl", 162: "cent", 163: "pound", 164: "curren",
  • 165: "yen", 166: "brvbar", 167: "sect", 168: "uml"

И на треть меньше этого:

  • "nbsp", "iexcl", "cent", "pound", "curren", "yen", "brvbar", "sect", "uml"

В пределах же всей таблицы, выгода может быть раза в 3-4.
Значений множество, поэтому дополнительные запятые и кавычки добавляют весьма внушительный размер.

Функция split работает очень быстро и на скорости исполнения практически не сказывается. Таблица создаётся только при инициализации сценария и в дальнейшем не пересчитывается, поэтому потери времени минимальны и составляют единицы миллисекунд (В моих тестах 0 миллисекунд).

P.S. Скорость можно повысить, а размер уменьшить, урезав сложения строк "+. Я пременил их для того, чтобы улучшить читаемость кода. В оригинальной функции - их нет.

Буду рад услышать мотивированные соображения по этому поводу или отчёты по тестам.


Автор: GreatRash, дата: 18 октября, 2010 - 15:42
#permalink

Теперь все понятно. Интересный способ, возьму на вооружение.


Автор: torbasow, дата: 23 октября, 2010 - 20:16
#permalink

Нельзя так писать; это трюкачество. Код должен быть ясным. Если нам нужен массив, следует писать массив. Об оптимизации должен заботиться компилятор, а если язык не компилируемый — значит упс, следует уповать на рост вычислительных мощностей, но не коверкать применяемый язык противоестественным образом.


Автор: vladlen, дата: 24 октября, 2010 - 00:31
#permalink

Поспешу не согласиться:
1. Этот сайт - хорошее место для обучения и это хороший пример как можно описать массив кратко и лаконично.
2. Такие записи можно и даже нужно использовать на момент инициализации. а вот во время выполнения баловаться такими конструкциями не желательно.
3. Самое узкое место - линии связи и наращивать их довольно проблематично
4. Если кому-то зачем-то понадобилось лезть в мой код с такими маниакальными извращениями, то этот человек должен полностью отдавать себе отчет в том что он хочет сделать. Если ему что-то не понятно то пора подучиться.
5. Автор очень грамотно заметил, функция самодостаточна и не требует модификации на протяжении достаточно большого количества времени.
Из всего вышеизложенного можно построить несколько тезисов:
1. Если так пишешь, то надо знать где, как и почему.
2. Решение универсальное, "оптимизированное" и не требующее изменений.
На сайте Лебедева в Техногрете есть статья по поводу того как писать не стоит, тут все куда нагляднее. И еще есть регулярки которые могут быть очень сложными и замысловатыми, да еще и оптимизированными, их тоже стоит менять на медленные и убогие чтобы удовлетворить разум несведущего?
З.Ы. Я вскользь прочитал учебник за 2 часа и этого времени вполне было достаточно для понимания этой конструкции.


Автор: I-zone, дата: 24 октября, 2010 - 20:05
#permalink

Здравствуйте, torbasow.
Подобное "трюкачество" можно наблюдаеть в таких проектах, как dojo, jquery, prototype. "Код должен быть ясным" - основной код обработки таблицы предельно ясен, с самой таблицей, возможно сложнее. Ну а к чему делать её читаемой, жертвуя на это ресурсы пользователя и сервера, если она никогда не изменится?
"Нельзя так писать" - моя точка зрения обратна вашей, я считаю, что писать размашистый объект в данном случае, имея возможность уменьщить его в разы - это настоящее издевательство над пользователем и как раз так - делать нельзя.
"это трюкачество" - весь клиентский код на javascript - это сплошное трюкачество. Приведу пару подобных конструкций для сокращения клиентского кода, которые в том числе, используются авторитетными framework'ами dojo, prototype, jquery:

//Короткие конструкции
  //1 indexOf
  if("widthheightmarginborderzoomopacitycolorfontSize".indexOf(name)>=0){}
  //2 regExp
  if(/^width|height|margin|border|zoom|opacity|color|fontSize$/.test(name)){}
//Классическая конструкция
  if(name==="width"||name==="height"||name==="margin"||name==="border"||name==="zoom"||name==="opacity"||name==="color"||name==="fontSize"){}

Кажется плюсы такого подхода очевидны. Обе конструкции в 2 раза легче, а RegExp конструкция читается проще, чем классическая.
Скажите пожалуйста, torbasow, чем это "трюкачество" вредит пользователю, серверу, интернет-провайдеру или девелоперу?
Подход к клиентскому коду - совсем другая печальная история, отличающаяся от серверной.


Автор: ixth, дата: 25 октября, 2010 - 14:21
#permalink

Размер функции — абсолютно бесполезная цель. Паковать код и отдавать его в deflate никто не запрещал. Преждевременная оптимизация, к тому же такого бесполезного параметра — зло. Способ объявления массива более-менее нормальный, но в том виде, в котором он представлен (с циклами, покрывающими массив частично) — не очень удобный.


Автор: I-zone, дата: 25 октября, 2010 - 17:03
#permalink

"Размер функции — абсолютно бесполезная цель" - 90% кода - функции. И цель очень даже полезная и благая.
"Преждевременная оптимизация" - а когда же наступит время оптимизации?
"к тому же такого бесполезного параметра — зло" - Почему же зло и почему параметр стал бесполезный? Если речь о таблице - это единственный элемент достойный оптимизации в этом коде.
"Паковать код и отдавать его в deflate никто не запрещал" - Естественно, а кто спорит. Пусть себе deflate пакует, а мы оптимизируем.
"не очень удобный" - для чего удобство? Повторюсь - таблица никогда не изменится.
"покрывающими массив частично" - Частично? И какую же часть?

Пишете абсурдные вещи. Может такими они не являются, просто вас сложно понять, ведь не одно предложение в тексте не аргументировано. Может быть поэтому возникает стойкое ощущение, что подобные высказывания лишены смысла. ixth, если не составит труда, объясните пожалуйста, что вы хотели сказать, кроме того, что вам лично не понравился способ объявления и дополнения таблицы? В чем конкретно минусы?


Автор: ixth, дата: 25 октября, 2010 - 17:14
#permalink

Ради бога, отдайте миницифакцию минификаторам!


Автор: I-zone, дата: 25 октября, 2010 - 18:17
#permalink

А почему нужно обязательно отдать минификацию минификаторам?
И с каких пор минификаторы умеют приводить объекты к подобному виду? Минифицированная таблица-оригинал имеет размер 8.2 КБ, оптимизированная таблица + 2 функции, обработанные минификатором YUI 2.4 КБ, а это в 3 с половиной раза меньше. Разве не заметен плюс?
Вы путаете процессы. Работу у минификатора я не отнимал, а вас попрежнему прошу написать, только объективно, в чём минус? Что работает не так? Чем плох метод? Напишите хотя бы одно пояснение.


Автор: ixth, дата: 25 октября, 2010 - 18:20
#permalink

А я говорил, что код работает не так? Код хорош и полезен, я просто не пойму зачем нужно уменьшать размер кода в ущерб читаемости. Я уверен, что ужав код в три раза, вы не добьетесь прироста производительности. А учитывая тот факт, что оба варианта — и Ваш и простой, описанный в виде хэша, в подавляющем большинстве случаев перед отправкой будут сжаты gzip'ом, разность в длине будет несущественной: один-два байта. Оно того стоит? Split возможно хорош в каких-то случаях, но как только я увидел бы в коде for-цикл, я бы от него отказался.
Еще раз задам основной вопрос: чем так хорош короткий код?


Автор: I-zone, дата: 25 октября, 2010 - 18:50
#permalink

"сжаты gzip'ом, разность в длине будет несущественной: один-два байта" - Уверены? Один байт - это один символ. Вы хотите сказать, что разность в объеме будет максимум 2 символа? Разность будет такая же - 30-35%, вы знакомы с алгоритмами сжатия?
- 35% это очень хороший показатель.
"ущерб читаемости" - читаемость этой таблицы - вещь не нужная, приходится повторить в пятый раз - таблица останется неизменной всегда!!!
"чем так хорош короткий код?" - тем, что он короток. Эта фраза вообще убивает. Извини конечно, но на мой взгляд - полная глупость.


Автор: ixth, дата: 25 октября, 2010 - 19:44
#permalink

Окей, я согласен: разность действительно составила порядка 20%, это существенно, но я уверен, что на большем файле с большим словарем она нивелируется. В любом случае, считаю, что те 400 байт в данном случае не сделают особой разницы.


Автор: I-zone, дата: 25 октября, 2010 - 20:03
#permalink

"разность действительно составила порядка 20%" - у меня немного другой код, потому и словарик другой получился. Разность составила 32%
А кто сказал, что следует минимизировать только одну, например из 1000 функций? Тут я выложил самодостаточную функцию, и именно поэтому постарался сжать её по максимуму! Если предпологается использовать её в купе с другим кодом, жмите всё, что можно (но не в ущерб производительности) и в сумме это будет несомненный плюс. И кто знает, может выйграете не 30, а 80 или даже 200%.
Хочешь, распишу тебе этот код в 5-10 раз шире. Он будет более читабельным, но надо ли? (это риторический вопрос)


Автор: ixth, дата: 25 октября, 2010 - 20:39
#permalink

Вы как-то исключительно фанатично относитесь к размерам. Я согласен, что оптимизация — это хорошо, я сам некоторое время назад баловался запихиванием всего в png-спрайты и пожатием получившегося оптимайзерами, но все-таки эти самые 400 байтов не стоят того. У Вас частный случай strtr, а вы из него столько шуму сделали split'ом. Вас действительно так беспокоят люди, сидящие на исключительно узком канале или размер для Вас — спортивная самоцель? Если так, то я ничего не имею против. Вы, кстати, слышали про js1k?


Автор: ixth, дата: 25 октября, 2010 - 20:42
#permalink

Исключительно интересная статья про победителя соревнования: http://marijnhaverbeke.nl/js1k.html


Автор: I-zone, дата: 25 октября, 2010 - 20:54
#permalink

А как код быстро работает. Мастер своего дела. Но только пользы нет от этих "игрушек"


Автор: I-zone, дата: 25 октября, 2010 - 21:18
#permalink

Моя цель делать код минимального размера с той же функциональностью. Считаю это правилом хорошего тона. Если можно - делаю. Многие библиотеки пишутся по этому же принципу. Считаю + коду, который написан максимально лаконично. Сам нелюблю, ждать загрузки многотонных скриптов, когда страница висит и ждёт их загрузки, ну а копейка - рубль бережёт. 400 байт, если жать, а если нет? А фанатизм не моё, режу только там, где это стоит делать css спрайты вещь весёлая, но они не экономят трафик, даже слегка наоборот. С их помощью избавляются от множества одновременных запросов к серверу))


Автор: yaroslav2 (не зарегистрирован), дата: 20 октября, 2010 - 15:13
#permalink

Не знал, что это называется "мнемоники", всегда называл их просто спецсимволами.


Автор: I-zone, дата: 20 октября, 2010 - 20:18
#permalink

Ну отчасти правильно
Спецсимволы: >, <, ", ', & частенько переводят в мнемоники.
В каждом языке есть свои "спецсимволы" и в каждом есть возможность их экранировать. В html экранируют мнемониками (html сущностями).

В том и суть статьи, что переводим не только спецсимволы, но и массу других, которые не просмотреть в документе с кодировкой windows-1251, но с помощью сущностей это возможно. Например любимый всеми &copy; (©) внизу страниц или множество пробелов &nbsp;. Даже на страницах сайта http://javascript.ru вы найдете множество сущностей, например:

<title>Разбираем понятие &quot;мнемоники&quot; на практике.</title>
<span style="padding-right: 20px;">&copy; Илья Кантор, 2007-2010</span>
<a href="http://javascript.ru/master-kiev" style="color:yellow">Мастер-классы <b>в Киеве</b>, 26 декабря! &raquo;&raquo;</a>
<td width="100%">&nbsp;</td>

Автор: blessmaster, дата: 14 ноября, 2010 - 01:05
#permalink

Боязнь двухбайтных кодировок - это прямо эпидемия какая-то.
Сначала экономим на байтах, которые очень хорошо сжимаются, в силу своей регулярности, а потом начинаем вставлять длинные цепочки символов, которые не очень хорошо читаются и по длине от пяти символов. В результате в исходниках чёрт ногу сломит, а выигрыш не очень и очевиден, если это не сайт посвящённый исключительно русской прозе.
UTF давно решил эту проблему, при том, что текст в нём читается нативно и выглядит "как есть", что в браузере, что в исходном коде.
Единственная польза - только от нескольких экранирующих последовательностей символов имеющих в коде особый смысл. В HTML это один набор, в SQL - другой, где-то ещё - третий.


Автор: I-zone, дата: 18 ноября, 2010 - 17:23
#permalink

Не думаю, что двухбайтных кодировок кто то боится.
UTF-8 благо интернета, но иногда нет выбора, какую кодировку использовать.
Видимо вы не видите, на что направлена статья. В жизни, ситуации и ограничения бывают разные. Данная статья - это не агитация по переходу на 8-ми битные кодировки, но если вы просто хотите поделиться своими знаниями в области кодировок и донести пару доводов, не лучше ли написать статью об этом?


Автор: KOLANICH, дата: 18 декабря, 2010 - 22:44
#permalink

а

$msg=htmlspecialchars($_POST["msg"]);

уже не пашед?


Автор: I-zone, дата: 22 декабря, 2010 - 11:05
#permalink

И вы смогли запустить это на клиенте?
К тому же вы сами столкнулись с некоторыми проблемами в теме base64, не так ли? А ведь эта функция может избавить вас от описанных проблем. На этом фоне ваш вопрос выглядит бессмысленным ;-)


Автор: Маэстро, дата: 15 сентября, 2011 - 22:13
#permalink

1. Преклоняюсь перед нервами автора статьи, который отстаивает свою точку зрения перед теми, которым не важен факт разработки хорошей функции, а важен факт хорошей читабельности функции!

2. Не уважаю тех, кто уводит дискуссию от сути статьи. Вы бы еще придрались к тому что название функции HTML.decode! А почему не MyFunction.decode??

3. Мне пришлось тоже столкнуться с ситуацией преобразования (декодирования) html-сущностей в символы. И ничего изящного в интернете я не нашел. Ваш код хоть и компактен, но работает только с уже выделенными отдельными последовательностями, а с целыми текстами - нет. То есть, для преобразования большого текста потребуется еще писать процедуру сканирования этого текста.
Я придумал (как мне кажется изящное) решение. Основано оно на уникальном свойстве элемента TEXTAREA. Этот элемент умеет сам перекодировать! Точнее, конечно это делает браузер. Итак, процесс сводится к трем строчкам:

var HTMLdecoder=document.createElement('textarea');
// этот элемент даже не надо вставлять в тело документа и скрывать

// для декодирования html-сущностей в простой текст выполняем всего две строчки:
 HTMLdecoder.innerHTML = somehtmltext; 
 var s = HTMLdecoder.value;

// примечание: никогда не присваивайте элементу HTMLdecoder.value = ... ничего! Иначе декодер перестанет работать.

Отправить комментарий

Приветствуются комментарии:
  • Полезные.
  • Дополняющие прочитанное.
  • Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены.
    Для остальных вопросов и обсуждений есть форум.
P.S. Лучшее "спасибо" - не комментарий, как все здорово, а рекомендация или ссылка на статью.
Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Разрешены HTML-таги: <strike> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <u> <i> <b> <pre> <img> <abbr> <blockquote> <h1> <h2> <h3> <h4> <h5> <p> <div> <span> <sub> <sup>
  • Строки и параграфы переносятся автоматически.
  • Текстовые смайлы будут заменены на графические.

Подробнее о форматировании

CAPTCHA
Антиспам
8 + 8 =
Введите результат. Например, для 1+3, введите 4.
 
Поиск по сайту
Другие записи этого автора
Больше записей нет. Прокомментируйте эту запись - может быть, тогда он что-нибудь еще хорошее напишет ;)
Содержание

Учебник javascript

Основные элементы языка

Сундучок с инструментами

Интерфейсы

Все об AJAX

Оптимизация

Разное

Дерево всех статей

Популярные таги
Последние комментарии
Последние темы на форуме
Forum