Статьи

Концы строк в Javascript

Я потратил большую часть сегодняшнего дня, борясь с окончаниями строк в Javascript, и в конечном итоге получил некоторые результаты, которые стоит поделиться — хотя бы для того, чтобы спасти других разработчиков от спуска в ту же чёрную дыру отладки.

Как вы, возможно, знаете, простой разрыв строки на самом деле имеет три формы в зависимости от того, какая операционная система выполняет разрыв. На машинах Unix, один символ новой строки ‘n’ делает эту работу. На Mac используется возврат каретки ‘r’. DOS и Windows используют оба: ‘rn’. Это одна из тех относительно тонких проблем, которая может сильно укусить вас, если вы не знаете, на что обратить внимание.

Сегодня передо мной стояла простая задача создания функции Javascript для преобразования отдельных строк новой строки в двойные строки внутри текстовой области. Моя первая попытка выглядела так:

var doublenewlinesRE = /([^n])n([^n])/g; function doublenewlines(obj) { obj.value = obj.value.replace(doublenewlinesRE, "$1nn$2"); } Double newlines

var doublenewlinesRE = /([^n])n([^n])/g; function doublenewlines(obj) { obj.value = obj.value.replace(doublenewlinesRE, "$1nn$2"); } Double newlines

Приведенный выше код использует простое регулярное выражение, которое находит все экземпляры чего-то, что НЕ является новой строкой, за которой следует новая строка, за которой следует что-то еще, не являющееся новой строкой. Экземпляры этого шаблона затем заменяются тем же шаблоном с двумя символами новой строки в середине вместо одного.

Это отлично работало в Firefox как на Windows, так и на Linux и Mac, потому что Firefox рассматривает переводы строк как ‘n’ независимо от того, на какой платформе он работает. Он сломался в IE для Windows и IE для Macintosh, потому что эти браузеры используют ‘rn’ и ‘r’ соответственно.

Справедливо. Обычное решение этой проблемы — нормализовать окончания строк перед выполнением преобразования, заменив каждую из трех комбинаций одним окончанием вашего предпочтения (в моем случае ‘n’). Вот моя вторая попытка функции:

function doublenewlines(obj) { obj.value = obj.value.replace(/(rn|r|n)/g, 'n'); obj.value = text.replace(doublenewlinesRE, "$1nn$2"); }

Это тоже не сработало. После долгих размышлений, отладки и ковыряния в окнах оповещений я наконец-то обнаружил недокументированную и почти безмолвную неясную «особенность» Internet Explorer: когда вы присваиваете строку атрибуту value входного объекта, IE тихо преобразует ваш nice ‘n окончание строки предпочтения платформы. В документации Microsoft об этом не говорится , но я подтвердил, что это происходит как в Windows, так и в Mac версиях Internet Explorer.

Bizzarely, если вы присваиваете атрибуту атрибута скрытого объекта поля формы, преобразование не происходит; окончания строк изменяются только при назначении текстовой области.

Следующий код, хотя он и внешне идентичен по функциям только что перечисленному коду, делает именно то, что я хочу:

function doublenewlines(obj) { var text = obj.value; text = text.replace(/(rn|r|n)/g, 'n'); obj.value = text.replace(doublenewlinesRE, "$1nn$2"); }

Это работает нормально, потому что нормализованная версия назначается переменной, а не назначается непосредственно атрибуту значения объекта textarea — следовательно, автоматическое преобразование окончания строки IE задерживается до конца сценария и не может разрушить мое второе регулярное выражение.

Наконец, заметка о стиле. Если бы я думал о повторном использовании кода, а не работал быстро для решения проблемы, я бы, вероятно, придумал что-то вроде этого:

function doublenewlines(text) { text = text.replace(/(rn|r|n)/g, 'n'); return text.replace(doublenewlinesRE, "$1nn$2"); }

Двойные переводы

Хотя для этого требуется немного больше кода в обработчике onclick, абстрагируясь только от строковой операции, я бы полностью избежал странной проблемы с преобразованием конца строки. Тем не менее, по крайней мере, я ушел с пониманием еще одной маленькой причуды IE.