Найти тему
Журнал «Код»

Ваш собственный орфокорректор с автозаменой

Оглавление

Про­ект неде­ли.

Ранее мы уже дела­ли редак­тор тек­ста с авто­за­ме­ной. Тогда исправ­ле­ни­ем тек­ста зани­ма­лась ней­ро­сеть Яндек­са, а мы лишь сде­ла­ли для это­го обо­лоч­ку. Минус под­хо­да в том, что какой-то меха­низм реша­ет за вас, какие сло­ва пра­виль­ные, а какие нуж­но заме­нить. Давай­те это испра­вим.

На этой неде­ле мы дела­ем орфо­кор­рек­тор, кото­рый будет рабо­тать по вашим пра­ви­лам. Вы сами реши­те, что и как заме­нять в тек­сте, и сами про­пи­ше­те нуж­ные пра­ви­ла. И при необ­хо­ди­мо­сти смо­же­те их допол­нять.

Это полез­но, напри­мер, для дело­вой пере­пис­ки: мене­джер пишет «Засунь­те себе в... свои прав­ки, это пол­ная чушь, я не буду это исправ­лять». А алго­ритм заме­ня­ет это на «Кол­ле­ги! Спа­си­бо за кон­струк­тив­ную кри­ти­ку! Нам потре­бу­ет­ся уточ­нить неко­то­рые момен­ты, преж­де чем мы возь­мем эти заме­ча­ния в рабо­ту».

Логи­ка будет такая:

  • берём код про­шло­го про­ек­та;
  • выки­ды­ва­ем из него всё, что свя­за­но с ней­рон­кой;
  • на это место заки­ды­ва­ем свой код, кото­рый меня­ет сло­ва и бук­вы, как нуж­но нам;
  • про­ве­ря­ем резуль­тат.

Регулярные выражения

Что­бы заме­нить одно сло­во на дру­гое, в JavaScript исполь­зу­ют функ­цию replace(), в кото­рой пишут сна­ча­ла, что нуж­но най­ти, а затем — на что заме­нить.

Напри­мер, s = s.replace('кто', 'что'); заме­нит в стро­ке сло­во «кто» на сло­во «что». Это удоб­но и вро­де как нам под­хо­дит, но смот­ри­те, какие есть мину­сы у это­го под­хо­да:

  • заме­ня­ет­ся толь­ко пер­вое най­ден­ное сло­во;
  • если «Кто» будет напи­са­но с боль­шой бук­вы, наша функ­ция его уже не най­дёт;
  • имя «Гек­тор» пре­вра­тит­ся в «Гечтор», а казах­стан­ский город Акто­бе пре­вра­тит­ся в «Ачто­бе».

Что­бы такой ерун­ды не про­ис­хо­ди­ло, исполь­зу­ют регу­ляр­ные выра­же­ния.

Регу­ляр­ное выра­же­ние мож­но пред­ста­вить как малень­кий встро­ен­ный язык про­грам­ми­ро­ва­ния, зато­чен­ный под поиск и обра­бот­ку тек­ста. У это­го язы­ка есть спе­ци­аль­ные коман­ды, кото­рые опре­де­ля­ют пове­де­ние алго­рит­ма. Эти коман­ды встра­и­ва­ют­ся в обыч­ный текст, и полу­ча­ют­ся регу­ляр­ные выра­же­ния.Несколь­ко при­ме­ров:

код — най­дёт про­сто эти бук­вы внут­ри любо­го сло­ва, в том чис­ле «нашко­дил».
\Bкод\B — най­дёт сло­во «код», окру­жён­ное про­бе­ла­ми или в нача­ле пред­ло­же­ния. Мар­кер \b озна­ча­ет гра­ни­цу сло­ва. И тут важ­ное заме­ча­ние: в JavaScript есть мар­кер \b, кото­рый обо­зна­ча­ет гра­ни­цу сло­ва на лати­ни­це и \B, кото­рый обо­зна­ча­ет гра­ни­цу сло­ва в осталь­ных алфа­ви­тах. А, напри­мер, на Python токен \b рабо­та­ет на всех язы­ках.
\B[Кк]од\B — най­дёт «Код» или «код» как отдель­ное сло­во. Бук­вы внут­ри квад­рат­ных ско­бок он вос­при­ни­ма­ет как «или». [Кк] озна­ча­ет «Либо заглав­ная К, либо строч­ная к».
\B[Кк]о\W\B — най­дёт «Код», «Кот», «Ком», «Кое», и так же со строч­ной бук­вы. Токен \w озна­ча­ет любую бук­ву сло­ва на лати­ни­це, а \W — на всех язы­ках.
\B[Кк]од\w{0,3}\B — най­дёт «Код», «Кода», «Коду», «Кодом», «Кода­ми» плюс то же самое со строч­ных букв. В фигур­ных скоб­ках ука­зы­ва­ют чис­ло воз­мож­ных повто­ров преды­ду­ще­го зна­ка. \w{0,3} озна­ча­ет «любая бук­ва, повто­рён­ная от нуля до трёх раз».
[\w-_\.]+@([\w-]+\.)+\w{2,5} — хе-хе-хе. Эта регу­ляр­ка помо­га­ет най­ти в тек­сте элек­трон­ные адре­са. Плю­сик озна­ча­ет «один или боль­ше», а скоб­ки исполь­зу­ют­ся, что­бы при­кре­пить плю­сик к набо­ру сим­во­лов. Пере­во­дит­ся так: «Сколько-то после­до­ва­тель­но­стей из букв, дефи­сов, под­чёр­ки­ва­ний и точек, потом соба­ка, потом сколько-то после­до­ва­тель­но­стей из букв, дефи­сов и точек, потом от двух до пяти букв. Если хоти­те, что­бы сра­ба­ты­ва­ли доме­ны типа .apartments, при­дет­ся ста­вить в кон­це десят­ку.
Обра­ти­те вни­ма­ние: плюс в регу­ляр­ках озна­ча­ет не «одно сло­жить с дру­гим», а «то, что напи­са­но пере­до мной, повто­рить один или мно­го раз».

Если раз­мет­ка регу­ляр­ных выра­же­ний вам сей­час кажет­ся слож­но­ва­той — не печаль­тесь. Мы сде­ла­ем об этом отдель­ную ста­тью. В реаль­но­сти там всё очень лег­ко, нуж­но лишь выучить несколь­ко спе­ци­аль­ных букв.

А пока что пол­ный спи­сок основ­ных команд и свойств регу­ляр­ных выра­же­ний мож­но посмот­реть на Хаб­ре или JavaScript.ru.

Регулярки в JavaScript

Что­бы JavaScript понял, что мы исполь­зу­ем регу­ляр­ные выра­же­ния вме­сто кон­крет­но­го сло­ва при поис­ке, исполь­зу­ют две косые чер­ты:

/регулярное выражение/флаги

Фла­ги — это спе­ци­аль­ные коман­ды для выра­же­ний, кото­рые дают им супер­спо­соб­но­сти: i — нечув­стви­тель­ность к реги­стру или g — поиск по всей стро­ке.

Вер­нём­ся к слу­чаю с Гек­то­ром. Что­бы при замене «кто» на «что» не воз­ни­ка­ло таких ситу­а­ций, доба­вим в функ­цию заме­ны регу­ляр­ное выра­же­ние:

s = s.replace(/\Bкто\B/gi, ' что ');

Вы уже зна­е­те, что \B озна­ча­ет гра­ни­цы сло­ва.

Флаг g озна­ча­ет, что мы прой­дём всю стро­ку и най­дём все сло­ва «кто», что­бы их заме­нить. А флаг i дела­ет наш поиск нечув­стви­тель­ным к реги­стру — он най­дёт и «Кто», и «ктО», и даже «КТО».

Теперь, когда мы это зна­ем, мы можем менять наш текст как угод­но:

  • про­сто менять один текст на дру­гой:

s = s.replace(/\Bкто\B/gi, 'что');

  • менять один сим­вол на дру­гой или на целое сло­во­со­че­та­ние

s = s.replace(/\Bя\B/gi, 'неизвестно кто');

  • Делать Каж­дое Сло­во Боль­шим:

s = s.replace(/\s[а-я]/g, u => u.toUpperCase());

Сра­зу ого­во­рим­ся: всё это рабо­та­ет пре­дель­но тупо, и, если мы ска­за­ли делать заме­ну на «что», то вез­де будет заме­на на «что» со строч­ной. Если мы хотим сохра­нить заглав­ные бук­вы, то заме­на будет в два шага:

s = s.replace(/\Bкто\B/g, 'что');

s = s.replace(/\BКто\B/g, 'Что');

Теперь у нас есть всё что нуж­но, что­бы сде­лать свой редак­тор с веж­ли­вы­ми авто­за­ме­на­ми.

Готовим каркас

Что­бы было быст­рее, возь­мём ста­рый код и убе­рём из него всё, что рабо­та­ло с ней­ро­кор­рек­то­ром.

Стра­ни­ца уже гото­ва, в ней толь­ко меня­ем имя скрип­та.

Каркас

Почи­сти­ли скрипт:

Настраиваем правила автозамены в скрипте

Пер­вое, что нам пона­до­бит­ся, — пере­мен­ная, что­бы хра­нить текст из поля вво­да, кото­рый мы будем обра­ба­ты­вать. Её мы поста­вим в самое нача­ло скрип­та:

// строковая переменная, чтобы хранить текст из поля ввода var s = '';

Теперь в обра­бот­чик нажа­тия вме­сто ней­ро­скрип­та поме­ща­ем наш код. Прин­цип такой: берём пере­мен­ную, при­ме­ня­ем на неё одно пра­ви­ло, пере­хо­дим к сле­ду­ю­ще­му. При каж­дом нажа­тии про­бе­ла или энте­ра наш код прой­дёт по всем пра­ви­лам и заме­нит нуж­ные сло­ва и сим­во­лы:

ГОТОВЫЙ СКРИПТ regexp.js

Резуль­тат рабо­ты скрип­та
Резуль­тат рабо­ты скрип­та

Что дальше

Воз­мож­но­сти регу­ля­рок прак­ти­че­ски без­гра­нич­ны. На них рабо­та­ют авто­кор­рек­то­ры, авто­ти­по­гра­фы и все те алго­рит­мы, кото­рым нуж­но меха­ни­че­ски обра­бо­тать текст по пра­ви­лам.

Сей­час наш алго­ритм очень про­стой: он не учи­ты­ва­ет рода и чис­ла, не пони­ма­ет зна­че­ний слов, а текст после него луч­ше пере­чи­тать, что­бы не сле­те­ли скло­не­ния и спря­же­ния. Но всё это реша­е­мо — доста­точ­но про­сто напи­сать мно­го новых пра­вил.

Подписывайтесь на наш канал, чтобы не знать предела совершенству!