Array  break  case  catch  const  continue  default  Date  do Error  else  Function  false  finally  for

function  if  in  instanceof  Infinity  Math  NaN  Number  new  null  Object  Promise  prototype  RegExp

return  String  switch  this  then  throw  try  true  undefined  var  with  while
	
alert(s)
appendChild(tagName)
fillRect()
pow(base, n)
sin(radians)
cos(radians)
random()
isNaN()
test()
sqrt(n)
prompt(s)
parseInt(s) parseFloat(s)
floor(f) 
ceil(f)
charAt(n)
indexOf(substring, offset)
substring(start, end)
replace(pattern, replacement)
toLowerCase(s)
toUpperCase(s)
abs(n)
splice(start, length, newItem1, newItem2, ...)
split(pattern, limit)
toString()
createElement(tagName)

getElementById(id)

getContext(contextType)

removeChild(domElement)

strokeText(text, x, y)

fillText(text, x, y)

measureText(text)

setItem(key, value)

join(delimeter)

round(floatNumber)
	

Строки

Строковая переменная может быть объявлена в JavaScript коде используя одинарные или двойные кавычки

function defineStringVar() {
	var name = 'Василий', surname = "Теркин";
}

Никакой разницы в переменных name и surname для интерпретатора JavaScript нет.

Первое задание

Дан произвольный текст. Отредактировать текст так, чтобы:

  • a) между словами был ровно один пробел;
  • b) предложения в тексте разделялись ровно двумя пробелами.

Для начала прочитайте исходный код программы, я старался писать очень подробные комментарии

function textCorrector() {
	var s = '', text = '';
	while (s != 'endtext') {//для начала считаем текст
		s = readln('Введите предложение текста, для окончания ввода введите слово endtext');
		if (s == 'endtext') {//Выходим до того, как присоединили 'endtext'
	 		break;
		}
		//text += s + "\n"; - более краткая запись, чем text = text + s + "\n";
		text += s + "\n"; //строки разделяем символами перехода на новую строку (\n)
	}
	var endSimbols = '.!?',     //символы, которыми может заканчиваться предложение
		breakSimbols = ' \t\n', //символы, которыми могут отделяться друг от друга слова и предложения
		i = 0, //счетчик для цикла
		char,  //буду хранить очередной символ
		result = '', //текст, который получится в результате работы программы
		previousIsBreak = false, //принимает true, когда предыдущий символ найден в breakSimbols
		previousChar = '8'; //предыдущий символ. мне подойдет любое значение не входящее в endSimbols и breakSimbols
	for (i; i < text.length; i++) {
		char = text.charAt(i);//получили очередной символ.
		if (!previousIsBreak && breakSimbols.indexOf(char) != -1) {
			previousIsBreak = true;
			char = ' ';//присваиваем символу пробел, так как слова и предложения по условию задачи должны разделяться пробелами
			if (i - 1 > -1) {
				previousChar = text.charAt(i - 1);
			}
			if (endSimbols.indexOf(previousChar) != -1) { //если предыдущим символом было окончание предложения
				char += ' '; //добавить еще один пробел
			}
			result = result + char;
			continue; // и перехожу к следующей итерации
		}
		if (breakSimbols.indexOf(char) == -1) { //если это не символ разрывающий слово или строку
			result += char;           //добавим его в результат
			previousIsBreak = false;  //и запомним, что предыдущий символ - не символ разрыва
		}
	}
	writeln("Исходный текст:\n" + text);
	writeln("\n====================================\n");
	writeln("Результат:\n" + result);
}

В первых строках программы (в первом цикле while) я показываю диалог для ввода строки текста. И продолжаю это делать до тех пор, пока пользователь не введет специальную строку endtext (я выбрал значение endtext, но в принципе это могло бы быть любым значением). Используя оператор + я могу "прицеплять" значение переменной s к окончанию переменной text. Также я цепляю символ перехода на новую строку "\n"

Каждую введенную пользователем строку я прикрепляю к переменной text. Когда этот процесс завершен, я перехожу к анализу строки. Я немного упростил себе задачу, приняв, что слова могут состоять из любых символов кроме пробела, символа разрыва строки \n и символа табуляции \t. По-хорошему надо было бы дополнить этот набор всевозможными скобками и кавычками, но мне что-то сегодня лень ). Энтузиасты могут заняться этим самостоятельно.

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

Далее, я прохожу по введенному тексту от начала до конца (я использую свойство length объекта типа String чтобы определить длину текста в символах). Позиции символов нумеруются с нуля до (length - 1), поэтому условие окончания цикла записано i < text.length а не i <= text.length.

Чтобы получить очередной символ строки, я использую метод объекта типа String сharAt. Описание всех свойств и методов, которые есть у переменных (объектов) типа String вы можете прочесть на сайте javasript.ru.

Получив значение очередного символа я первым делом проверяю, не был ли предыдущий символом разрыва строки и не входит ли текущий символ в группу символов разрыва строки?

if (!previousIsBreak && breakSimbols.indexOf(char) != -1) {

Я использую для этого метод indexOf. Метод возвращает позицию первого символа переданной в качестве аргумента подстроки в строке, для которой он вызывается. Если подстрока в строке не найдена, метод вернет значение -1, иначе вернет порядковый номер символа. Напомню еще раз, что символы в строке нумеруются с нуля.

Если условие (его можно еще "перевести" как "предыдущий символ был частью слова или предложения и текущий - не часть слова или предложения") выполнилось, я первым делом запоминаю для будущей итерации, что у нас текущий символ - символ разрыва. То, что у нас сейчас текущее, в следующей итерации станет предыдущим. Поэтому я присваиваю переменной previousIsBreak значение true. Текущему символу char я присваиваю значение "пробел" (" "), так как слова по условиям задачи должны разделяться пробелом, а символом разрыва могли быть и другие символы.

В следующем условном операторе

if (i - 1 > -1)

проверяю, существует ли предыдущий символ (например при i== 0 (i равном 0) его не существует). А если существует, получаю его и проверяю, не входит ли он в число символов, которыми может закончиться предложение. Если входит, добавляю к своей переменной char еще один пробел, так как предложения должны быть разделены двумя пробелами по условию задачи. После чего добавляю char к результирующей строке и перехожу к следующей итерации используя слово continue.

Далее, так как я установил previousIsBreak в true я не войду в условие в 19-ой строке, пока не встречу символ не являющийся символом разрыва. Тогда я войду в условие

if (breakSimbols.indexOf(char) == -1)

где добавлю этот очередной символ к строке - результату и заодно сброшу логическую переменную previousIsBreak в false. Таким образом, даже если где-то будет более чем один пробел между словами или всего один пробел между предложениями, в результате все равно их будет ровно сколько, сколько требует задача.

Ну и в конце концов я вывожу оба текста: тот, что был введен и тот, что получился после обработки.

Преимущества использования методов объекта типа String. Немного о регулярных выражениях

Рассмотрим следующую задачу:

Дана строка символов. Преобразовать ее, заменив все двоеточия (:), встречающиеся среди первых n/2 символов, на точку с запятой (;), и заменив точками все восклицательные знаки, встречающиеся среди символов, стоящих после n/2 символов.

Я мог бы решить эту задачу подобно предыдущей: пройти всю строку по символьно, заменяя двоеточие на точку с запятой в первой части и делая требуемую замену во второй части.

Но эта задача прекрасный кандидат на то, чтобы использовать только методы класса String при ее решении.

function replaceSimbols() {
	var inputText = 'Я сказал: Чтобы не маяться с вводом с клавиатуры, напишу строку один раз.',
		middle = Math.floor(inputText.length / 2), //середина строки, чтобы избежать дробного числа округлили вниз
		head = inputText.substring(0, middle), //подстрока от начала до середины
		tail = inputText.substring(middle); //подстрока от середины до конца
	head = head.replace(':', ';'); //заменили  двоеточие на точку с запятой
	tail = tail.replace('.', '!'); //заменили  точку на восклицательный знак
	writeln(head + tail);
}

Здесь первым делом я определил какую-то строку, содержащую двоеточие и точку.

Затем, я использовал округление вниз числа, равного длине строки разделенной на два, чтобы определить середину строки. Далее, я использовал метод substring чтобы получить первую половину строки и вторую. Я поместил их в переменные, которые назвал "голова" и "хвост" (head и tail). Ну и в конце концов я вызвал для этих переменных метод String replace, который возвращает значение той переменной, для которой он вызван, заменив однако подстроку переданную в первом аргументе на подстроку переданную во втором аргументе.

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

Однако, что было бы, если бы в моем примере строка заканчивалась многоточием? Или содержала бы два предложения заканчивающихся точкой?

Вы можете изменить в коде значение переменной inputText и убедиться, что в таком случае будет заменена только первая точка. Но этого можно избежать, если передать replace в качестве первого аргумента не строку, а регулярное выражение. Регулярные выражения - штука непростая. Вы можете прочитать о них здесь, здесь, здесь и здесь. Но мне для моей цели нужны очень простые регулярные выражения:

function replaceSimbols() {
	var inputText = 'Я сказал: Чтобы не маяться с вводом с клавиатуры, напишу строку один раз. А это еще предложение.',
		middle = Math.floor(inputText.length / 2), //середина строки, чтобы избежать дробного числа округлили вниз
		head = inputText.substring(0, middle), //подстрока от начала до середины
		tail = inputText.substring(middle); //пдстрока от середины до конца
	head = head.replace(/:/g, ';'); //заменили все двоеточия на точки с запятыми
	tail = tail.replace(/\./g, '!'); //заменили все точки на восклицательные знаки
	writeln(head + tail);
}

В head.replace я использую простейшее регулярное выражение вместо подстроки ':'. Оно выглядит как /:/g

В JavaScript регулярное выражение можно определить записав его шаблон между символами / и /. Так как меня интересует двоеточие в строке, его я и пишу между символами //. Символ g после закрывающего / говорит о том, что надо заменить все вхождения описанного между // шаблона.

В tail.replace чуточку сложнее: дело в том, что символ '.' в шаблоне регулярных выражений имеет специальное значение "любой символ". Поэтому, чтобы показать, что я имею ввиду именно точку, а не любой символ я поставил перед точкой обратный слеш \.

Третье задание

Присвоить литерным переменным с2, с1 и с0 соответственно левую, среднюю и правую цифры трехзначного числа k.

Ну тут все очень просто:

function parseThreeNumber () {
	"use strict"
	var k = parseInt( readln("Введите трехзначное целое число") ),
		c0, c1, c2, errorMessage = 'k не целое трехзначное целое число!', s;
	if (!k) {
		writeln(errorMessage);
		return;
	}
	s = String(k);
	if (s.length != 3) {
		writeln(errorMessage);
		return;
	}
	c2 = s.charAt(0);
	c1 = s.charAt(1);
	c0 = s.charAt(2);
}

В этом примере может быть неясен только один момент:

s = String(k);

Дело в том, что для чтения введенной пользователем переменной k мы используем parseInt, чтобы обеспечить контроль за вводимым значением. Благодаря этому в переменную k записывается объект типа Number. Но у таких объектов нет свойства length, которое можно использовать, чтобы определить количество знаков в числе. Поэтому я вызываю конструктор String и передаю ему наше число k. В результате в переменную s запишется строка, а для неё мы уже можем вызвать метод String charAt.

Заодно здесь можно разъяснить что такое "литерная переменная" из текста задачи. Дело в том, что эти задачки писались для выполнения на языках программирования Pascal или C++. В этих языках нельзя, как в JavaScript объявить переменную, а потом хранить в ней значение любого типа. Там если вы объявили переменную типа строка, значит в ней могут быть только строки, если объявил переменную типа целое число, значит в ней могут быть только целые числа. А если вам надо хранить один символ строки, для этого можно использовать переменные специального типа, который и назван литерным.

Тест на новые слова

  • Несохраненный_файл.js
Строка: 0, Символ: 0

  • {name}
  • У вас пока нет файлов
 

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

 

Правильно!

Не забывайте переодически проходить этот тест по мере чтения новых статей.

 

Ошибка!

 

Осталось: 0 сек.

Health:

Score:

 

Что значит:

 

 

 


Информация

Загрузите файл с исходным кодом программы на языке яваскрипт.

Файл должен содержать одну главную функцию, имя которой должно совпадать с именем файла.

Например, файл называется task1.js, имя главной функции должно быть task1.

Все остальные функции должны быть определены внутри главной.

*

Информация

Сохраняемый код должен содержать одну главную функцию.

Например:

function myFirstProgram() {
	//Тут все остальное, включая вспомогательные функции
}
					




Простой пароль
Пароли не совпадают