Посимвольное сравнение строк в java
Мне дали задание сравнить две строки посимвольно и вывести на экран отличающиеся символы. Как я понял String в Java не является массивом со строковыми символами(надеюсь правильно дал определение). Так как реализовать тогда такую задачу на Java?
Лучшие ответы ( 1 )
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:
Посимвольное сравнение 2 файлов
Полное задание:Реализация посимвольного сравнения двух файлов или страниц в интернете. Выводить.
Сравнение слов в массиве строк Java
Добрый день! Помогите пожалуйста с задачей.) "В файле содержатся фамилии людей. Нужно считать их из.
Сравнение строк (String) в java. Мини гайд для начинающих
Всем привет! Одна из самых распространенных ошибок начинающих, выражаемая в очень частых темах.
Посимвольное сравнение строк
Как в C# сравнить две строки (тип string) посимвольно так, что результатом сравнения будет число.
406 / 278 / 93
Регистрация: 14.03.2017
Сообщений: 777
Сообщение от Starlight_
String в Java не является массивом
еще как является
2479 / 1930 / 484
Регистрация: 17.02.2014
Сообщений: 9,207
у String есть метод toCharArray(), глянь на него))
295 / 468 / 86
Регистрация: 26.02.2018
Сообщений: 931
Записей в блоге: 2
Сообщение было отмечено Starlight_ как решение
Решение
Starlight_,
Вариант1.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
public static void main(String[] args){ String s = "dfgjsdrhgjsdrfhgjkdrfhgvui"; String s1 = "dfshdfhgfnfgnbfjkbndkldklf"; for(int i = 0; i Math.min(s.length(), s1.length()); i++){ String str = i Math.min(s.length(), s1.length()) - 1 ? s.substring(i, i + 1) : s.substring(i); String str1 = i Math.min(s.length(), s1.length()) - 1 ? s1.substring(i, i + 1) : s1.substring(i); if(!str.equals(str1)){ System.out.println("строка 1 символ" + i + " " + str + "-->" + "строка 2 символ" + i + " " + str1); } if(i == Math.min(s.length(), s1.length()) - 1){ i++; System.out.println(s.length() > i ? ("строка 1 субстрока" + s.substring(i) + "-->" + "строка 2 NON") : ("строка 2 субстрока" + s1.substring(i) + "-->" + "строка 1 NON")); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
public static void main(String[] args){ char[] s = "dfgjsdrhgjsdrfhgjkdrfhgvui".toCharArray(); char[] s1 = "dfshdfhgfnfgnbfjkbndkldklf".toCharArray(); for(int i = 0; i Math.min(s.length, s1.length); i++){ if(s[i] != s1[i]){ System.out.println("строка 1 символ" + i + " " + s[i] + "-->" + "строка 2 символ" + i + " " + s1[i]); } if(i == Math.min(s.length, s1.length) - 1){ i++; System.out.println(s.length > i ? ("строка 1 субстрока" + substring(s, i) + "строка 2 NON") : ("строка 2 субстрока" + substring(s1, i) + "строка 1 NON")); } } } private static String substring(char[] s1, int i) { String s = ""; for(int a = i; a s1.length; a++){ s += s1[a]; } return s; }
Строки в Java (class java.lang.String)
Путь программиста – сложный и долгий процесс. И в большинстве случаев начинается он с программы, которая выводит Hello World на экран. Java не исключение (см. Lesson: The «Hello World!» Application). Как мы видим, вывод сообщения осуществляется при помощи System.out.println(«Hello World!»); Если посмотреть в Java API, то метод System.out.println принимает входным параметром String. Про этот тип данных и пойдёт речь.
String как последовательность символов
Собственно, String в переводе с английского – строка. Так и есть, тип String представляет текстовую строку. А чем же является текстовая строка? Текстовая строка — это какая-то упорядоченная последовательность символов, которые идут друг за другом. Символ – char. Последовательность – sequence. Так что да, абсолютно правильно, String является реализацией java.lang.CharSequence . А если заглянуть внутрь самого класса String, то внутри него ничто иное как массив char’ов: private final char value[]; У java.lang.CharSequence довольно простой контракт:
У нас есть метод получения количества элементов, получения конкретного элемента и получения набора элементов + непосредственно сам метод toString, который вернёт this) Интереснее разобраться в методах, которые пришли к нам в Java 8, а это: chars() и codePoints() Вспоминаем по Tutorial от Oracle «Primitive Data Types», что char — это single 16-bit Unicode character .То есть по сути char это просто тип размером в половину типа int (32 бита), который представляет числа от 0 до 65535 (см. decimal значения в ASCII Table). То есть при желании мы можем char представить в виде int. И в Java 8 этим воспользовались. Начиная с 8 версии Java у нас появляется IntStream — стрим для работы с примитивными int’ами. Поэтому в charSequence есть возможность получить IntStream, представляющий или char’ы или codePoint’ы. Прежде чем перейдём к ним, увидим пример, чтобы показать всё удобство этого подхода. Воспользуемся Tutorialspoint online java compiler’ом и выполним код:
public static void main(String []args)
Теперь таким незамысловатым способом можно получить кол-во уникальных символов.
CodePoints
Итак, про chars мы увидели. Теперь непонятно, что за code points такие. Понятие codePoint появилось потому, что когда Java появилась, то хватало 16 бит (половина int) чтобы закодировть символ. Поэтому char в java представлен в UTF-16 формате («Unicode 88» specification). Позже повяился Unicode 2.0, концепция которого заключалась в представлении символа в виде сурогатной пары (2 чаров). Это позволило расширить диапазон возможных значений до значения int. Подробнее см. на stackoverflow: «Comparing a char to a code-point?». Про UTF-16 так же указано и в JavaDoc к Character . Там же, в JavaDoc, сказано, что: In this representation, supplementary characters are represented as a pair of char values, the first from the high-surrogates range, (\uD800-\uDBFF), the second from the low-surrogates range (\uDC00-\uDFFF). На стандартных алфавитах довольно трудно (а может даже нельзя) воспроизвести это. Но символы буквами и цифрами не заканчиваются. В японии придумали такую сложную для кодировок штуку, как emoji — язык идеограмм и смайликов. Есть про это интересная статья на википедии: «Эмодзи». Найдём пример emoji, например такой: «Emoji Ghost». Как мы видим, там даже указан тот самый codePoint (значение = U+1F47B). Указан он в шестнадцатеричном формате. Если перевести в десятичное число, то получим 128123. Это больше, чем позволяет 16 бит (т.е. больше чем 65535). Скопируем его:
К сожалению, платформа JavaRush не поддерживает такие символы в тексте. Поэтому, в пример ниже нужно будет в String вставить значение. Поэтому, теперь нам будет понятен простой тест:
public static void main(String []args) < String emojiString = "Вставте сюда эмоджи через ctrl+v"; //На один emojiString приходится 2 чара (т.к. не влезает в 16 бит) System.out.println(emojiString.codePoints().count()); //1 System.out.println(emojiString.chars().count()); //2 >
Как видно, в данном случае 1 codePoint идёт за 2 char’а. Вот такая вот магия.
Character
Как мы увидели выше, String’и в Java состоят из char. Примитивный тип позволяет хранить значение, а вот обёртка java.lang.Character над примитивным типом позволяет сделать много полезного с этим символом. Например, мы можем перевести строку в верхний регистр:
public static void main(String[] args) < String line = "организация объединённых наций"; char[] chars = line.toCharArray(); for (int i = 0; i < chars.length; i++) < if (i == 0 || chars[i - 1] == ' ') < chars[i] = Character.toUpperCase(chars[i]); >> System.out.println(new String(chars)); >
Ну и разные интересности: isAlphabetic() , isLetter() , isSpaceChar() , isDigit() , isUpperCase() , isMirrored() (например, скобки. ‘(‘ имеет зеркальное отражение ‘)’).
String Pool
Строки в Java неизменяемы, то есть константны. В том числе об этом указано в самом JavaDoc класса java.lang.String. Второе и тоже очень важное – строки могут задаваться литералами:
String literalString = "Hello, World!"; String literalString = "Hello, World!";
- Не будут создаваться однотипные объекты
- Сравнение по ссылке быстрее, чем посимвольное сравнение через equals
public static void main(String[] args)
Как видите, строки одинаковые, но результат будет false. А всё потому, что == сравнивает не по значению, а по ссылке. А вот так работает:
public static void main(String[] args)
Только заметим, что new String всё равно мы сделаем. То есть intern нам вернёт String из кэша, а вот изначальный String, по которому мы искали в кэше, будет выброшен на очистку, т.к. никто больше про него не знает. На лицо лишнее потребление ресурсов =( Поэтому, сравнивать строки нужно всегда через equals, чтобы уйти по возможности от внезапных и трудно определяемых ошибок.
public static void main(String[] args)
Equals выполняет посимвольное сравнивание строк.
Конкатенация
Как мы помним, строки можно складывать. И как мы помним строки у нас неизменяемы. Так как же тогда это работает? Всё верно, создаётся новая строка, которая состоит из символов складываемых объектов. Существует миллион версий о том, как работает конкатенация через плюс. Кто-то считает что будет каждый раз новый объект, кто-то считает что будет ещё что-то. Но прав может быть кто-то один. И этот кто-то – компилятор javac. Воспользуемся сервисом онлайн компилятора и выполним:
public class HelloWorld < public static void main(String[] args) < String helloMessage = "Hello, "; String target = "World"; System.out.println(helloMessage + target); >>
Теперь сохраним это как zip архив, извлечём в каталог и выполним: javap –c HelloWorld И тут мы всё узнаем:
В цикле, конечно, лучше делать конкатенацию через StringBuilder самим. И не потому что какая-то магия, а чтобы StringBuilder создавался до цикла, а в самом цикле происходил только append. Кстати, тут есть ещё одна интересность. Есть отличная статья: «Обработка строк в Java. Часть I: String, StringBuffer, StringBuilder». Много полезного в комментариях. Например, указано, что при конкатенации вида new StringBuilder().append(). toString() действует intrinsic оптимизация, регулируемая опцией -XX:+OptimizeStringConcat, которая по умолчанию включена. intrinsic — переводится как «внутренний». Такие вещи JVM обрабатывает особенным образом, обрабатывая их как Native, только без дополнительных затрат на JNI. Подробнее: «Intrinsic Methods in HotSpot VM».
StringBuilder и StringBuffer
Как мы выше видели, StringBuilder очень полезный инструмент. Строки являются immutable, т.е. неизменяемыми. А складывать хочется. Поэтому, нам в помощь даны 2 класса: StringBuilder и StringBuffer. Основное отличие между ними в том, что StringBuffer появился в JDK1.0, в то время как StringBuilder пришёл в java 1.5 как не синхронизированная версия StringBuffer, чтобы снять повышенные затраты на ненужную синхронизацию методов. Оба эти классы являются реализацией абстрактного класса AbstractStringBuilder — A mutable sequence of characters. Внутри хранится массив чаров, который расширяется по правилу: value.length * 2 + 2. По умолчанию размер (capacity) у StringBuilder’а равен 16.
Comparable
Строки являются comparable, т.е. реализуют метод compareTo. Выполняется это при помощи посимвольного сравнения. Интересно, что из двух строк выбирается минимальная длинна и по ней выполняется цикл. Поэтому, compareTo вернёт или разницу между int значениями первых несовпавших символов в пределе наименьшей из длинн строк, либо вернёт разницу между длиннами строк, если в пределах минимальной длинны строки все символы совпадают. Такое сравнение называется «лексикографическим».
Работа со строками Java
String имеет множество полезных методов:
На работу со строками сущесвует множество задач. Например, на Coding Bat. Так же есть курс на coursera: «Algorithms on Strings».
Заключение
Даже небольшой обзор данного класса занимает внушительное место. А это ещё не всё. Настоятельно рекомендую к просмотру доклад с JPoint 2015 года: Алексей Шипилёв — Катехизис java.lang.String
Java посимвольный вывод, запись в файл
Как после ввода слова, вывести в консоль все буквы а не только первую? С применением forEach не получиться решить второй вопрос по моему.
̶К̶а̶к̶ ̶з̶а̶п̶и̶с̶а̶т̶ь̶ ̶в̶с̶е̶ ̶п̶о̶л̶у̶ч̶е̶н̶н̶ы̶е̶ ̶д̶а̶н̶н̶ы̶е̶ ̶в̶ ̶ф̶а̶й̶л̶?̶ ̶А̶ ̶н̶е̶ ̶в̶в̶е̶д̶е̶н̶н̶у̶ю̶ ̶п̶е̶р̶в̶у̶ю̶ ̶б̶у̶к̶в̶у̶ ̶и̶з̶ ̶с̶л̶о̶в̶а̶.̶ Желательно что бы запись происходила по команде. Пример: ввел «-o» записал данные в файл.
Отслеживать
18.5k 4 4 золотых знака 31 31 серебряный знак 45 45 бронзовых знаков
задан 16 ноя 2018 в 1:34
3 2 2 бронзовых знака
Проблему с записью частично решил гениальным костылем. recorder.write(x); recorder.write(» «); recorder.write(Integer.toString(x)); recorder.write(» «); recorder.write(Integer.toBinaryString(x)); recorder.write(» «); recorder.write(Integer.toOctalString(x));
16 ноя 2018 в 2:00
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Пройтись циклом по строке можно с помощью String.toCharArray :
//объявим recorder перед циклом //обернем его в try, так он закроется по завершении блока без recorder.close try(FileWriter recorder = new FileWriter("text.txt")) < String line = reader.nextLine().trim(); for(char x : line.toCharArray()) < //выводим в консоль System.out.println("Буква: '" + x + "'"); //. //выводим в файл recorder.write(x); >> catch (IOException ex)
Судя по Вашему комментарию, формат вывода данных в консоль и в файл отличаются, поэтому писать нужно будет раздельно. Если нужно писать ровно одно и то же как в файл, так и в консоль, то можно написать для этого метод:
private static void writeToFileAndConsole(FileWriter writer, String line) throws IOException
И везде использовать его:
writeToFileAndConsole(recorder, "Буква: '" + x + "'");
Вместо FileWriter можно использовать PrintStream или PrintWriter , которые содержат готовые методы для вывода строки.
Желательно что бы запись происходила по команде. Пример: ввел «-o» записал данные в файл.
Для этого нужно читать ввод, проверять его и в зависимости от него выводить в файл. В любом случае это уже другой вопрос.
Класс String
чтение строк с клавиатуры
Объекты класса String, то есть строки, очень удобно склеивать друг с другом оператором плюс. Эта возможность введена специально для облегчения работы именно со строками, и для большинства других классов оператор плюс не определен.
String first_name = "Ivan"; String second_name = "Kuznetzov"; // С помощью оператора + можно склеивать строки - получится снова строка. // Эту строку можно сохранить в переменной, например, так: String full_name = first_name + " " + second_name; // Можно делать склейку прямо при распечатке System.out.println (first_name + " " + second_name); // Если написать строка плюс число, то число тоже приклеится к строке: int house_number = 204; String address = "Mayakovskaya street, " + house_number; System.out.println (address); // Распечатается: Mayakovskaya street, 204 // Можно использовать + и непосредственно при распечатке: double pi = 3.1415; System.out.println ("Число Пи примерно равно " + pi); // Также + хорош для перевода числа в строку: int number = 10; String str = number + ""; // приклеим 10 к пустой строке, получим строку '1', '0'
Ещё в классе String есть множество полезных функций. Например, уже знакомая нам charAt возвращает код символа, стоящего в строке под заданным номером. Нумерация как всегда в Java идет с нуля, а не с привычной единицы.
String name = "Ivan"; // charAt возвращает код символа под заданным номером. // Это именно код, поэтому charAt возвращает int, но его можно явно привести к char, // чтобы пользоваться уже как символом, в том числе распечатывать char c0 = (char) name.charAt (0); // с0 теперь равно 'I' - нулевой символ строки Ivan char c1 = (char) name.charAt (1); // с1 будет равно 'v' char c2 = (char) name.charAt (2); // с2 будет равно 'a' char c3 = (char) name.charAt (3); // с3 будет равно 'n' // в строке Ivan всего 4 символа, от нулевого до третьего, // поэтому обращение к четвертому повлечет ошибку: char c4 = (char) name.charAt (4); // исключение out of bounds, // то есть символ с индексом 4 вне границ строки. // На экране вы увидите красную надпись: "java.lang.StringIndexOutOfBoundsException: String index out of range: 4" // Не пугайтесь экрана с кучей непонятного текста - ищите ключевые знакомые куски // Например, IndexOutOfBounds точно означает выход за границу, а остальное уже детали
Строчки удобно считывать с клавиатуры с помощью уже знакомого класса Scanner:
Scanner myscan = new Scanner (System.in); // функция сканера next() возвращает очередное слово, // которое пользователь вводит с клавиатуры: String word = myscan.next (); // считать строчку до ближайшего пробела или enter // функция сканера next() считает целую строку до ближайшего enter: String line = myscan.nextLine ();
Для сравнения строк друг с другом в классе String есть функция equals. Она возвращает true, когда две строчки совпадают по буквам, и false, если хоть как-то отличаются. Обычный оператор сравнения == следует использовать только для переменных примитивных типов, таких как int, double, char, boolean. Для строк и вообще для объектов любых классов оператор == обычно будет работать неверно, но об этом в следующем блоке, где речь пойдёт о классах и объектах. Пока что лучше просто использовать equals вот так:
Scanner myscan = new Scanner (System.in); String line1 = myscan.nextLine (); // считать первую строчку с клавиатуры String line2 = myscan.nextLine (); // считать вторую строчку с клавиатуры if (line1.equals (line2) == true) System.out.println ("Были введены одинаковые строчки"); else System.out.println ("Были введены разные строчки"); // если в операторе if не указывать никакое сравнение, то // автоматически будет подразумеваться проверка выражения на истинность, // то есть == true допишется по умолчанию, даже если его не писать. // Так что следующие строчки делают то же самое, но запись чуть-чуть короче: if (line1.equals (line2)) // "если line1 равна line2, то" - код читается легче System.out.println ("Были введены одинаковые строчки"); else System.out.println ("Были введены разные строчки"); // Функция equals вызывается для какой-то заданной строчки: line1.equals () , // То есть вызов можно прочесть как "равна ли строка line 1?" // Сразу напрашивается - равна ли, а чему именно? Конечно другой строчке - // она указывается параметром функции equals.
Общий принцип работы с функциями строк.
Сначала вам нужно создать первую строчку String line1 = . явно указать её в двойных кавычках или прочесть её с клавиатуры через Scanner. Для этой строчки можно вызывать любые функции класса String через точку line1.имя_функции () . Если нужно, в скобках указываем параметры — числа, или другую строку. Как и раньше, чтобы использовать возвращаемое значение, его нужно объявить как переменную. Например, int res = line1.length (); позволит сохранить длину строки line1 в переменную res .
Чтобы описать, как устроена та или иная функция обычно приводят её прототип, то есть краткое описание. В прототипе слева указывается, каков тип возвращаемого значения функции, то есть она возвращает int, boolean, String или что-то ещё. Если же функция не возвращает ничего, то указывается английское слово «пустота» — void. После этого пишут имя функции, а затем в скобках её параметры.
Несколько прототипов функций класса String:
Функция boolean contains (String str) проверяет, содержится ли строчка-параметр в исходной строке и возвращает true, если содержится, и false иначе.
Функция int indexOf (String str) также ищет одну строчку или отдельную букву в другой строке и возвращает позицию, где именно вторая строчка встретилась в первой. Возвращает -1, если не встретилась совсем. Незаменимая вещь для любых текстовых редакторов и вообще работы с текстом.
Ещё вариант той же функции int indexOf (String str, int start_from) — делает то же самое, но ищет вхождение str только начиная с символа под номером start_from.
Функция int compareTo (String str) сравнивает одну строку с другой по принципу «как в словаре». То есть, для полностью равных строк возвращает ноль, если исходная строка шла бы в словаре раньше параметра, то функция вернет отрицательное число, а если позже — положительное.
Функция int length () возвращает длину строки, то есть количество символов в строке.
Функция String substring (int begin, int end) возвращает подстроку в заданных пределах. То есть, например, вы хотите работать не со всей строкой, а только с её частью, начиная с символа номер 5 и заканчивая символом номер 10, тогда пишем String res = line1.substring (5, 10);
В дополнение к уже описанной функции boolean equals (String str), сравнивающей строки на посимвольное равенство, есть ещё похожая функция boolean equalsIgnoreCase (String str), которая вернёт true, если строки одинаковые, но некоторые буквы указаны в одной строке заглавными, а в другой прописными.
Класс String специально сделан, чтобы хранить неизменяемые строки. Все функции от contains до substring не меняют содержимое данной строки, но могут генерировать новые строчки. Для изменения строк есть класс StringBuilder, но о нём пока рано вести речь.
Посмотрим пример на все эти функции сразу в коде:
// Мы могли бы считать строки с клавиатуры // Scanner myscan = new Scanner (System.in); // String line1 = myscan.nextLine (); // String line2 = myscan.nextLine (); System.out.println ("Введите адрес"); // Но сейчас для наглядности зададим конкретные значения: String address = "город Москва, улица Маяковская, дом 10"; // если в адресе есть слово "Москва", то . if ( address.contains ("Москва")) System.out.println ( "Совершите покупку всего за 100$" ); else System.out.println ( "Совершите покупку всего за 10$ " ); // шутка конечно :) // вычислим длину строки: int len = address.length (); System.out.println ("Вы ввели следующее количество символов: " + len); int begin = address.indexOf(","); // найдём первую запятую - с неё начинается улица в адресе System.out.println ("Первая запятая в тексте встречается на позиции " + begin); int end = address.indexOf(",", begin + 1); // искать вторую запятую после первой запятой String street = address.substring (begin+1, end); // выделим часть строчки с описанием улицы System.out.println ("Введенная улица: " + street); // распечатает "улица Маяковская"
В классе String есть одна функция, которую можно вызывать не для какой-то конкретной строки line1 или address, как было выше, а просто по имени класса String. Речь идёт о функции valueOf. Она принимает на вход число и возвращает его же, но в виде строки. Очень удобно, когда вам нужно перевести число в строку. Используется она так:
String number_str = String.valueOf (4.5); // было число double 4.5, а стала строка String number_str из трёх символов '4', '.', '5' // Java допускает и вызов через конкретный объект, как мы делали раньше: String line1 = "something"; String number_str2 = line1.valueOf (4.5); // так можно, но не обязательно // можно вызвать valueOf и для исходной строки line1, но смысла в этом мало - // всё равно line1 никак не используется. // Для таких функций можно просто указывать имя класса, в данном случае String //Можно вызывать valueIOf и для целых чисел и для других типов: String integer_str = String.valueOf (10); // вызывали прямо по имени класса String.valueOf // Функции, которые можно вызывать по имени класса называются статическими - static.
По логике вещей для valueOf нужен параметр — число, из которого потом будет получена строка, но никак не нужна сама исходная строка, ведь её ещё только предстоит сделать.
Фразу «строка класса String» формальнее можно пересказать как «объект класса String«. Точно также и для всех остальных классов можно создавать их объекты. Например, объектом класса File будет очередной файл на компьютере. То есть класс описывает целое понятие файлов в принципе, а объект класса — один конкретный файл в заданной папке. В будущих блоках мы научимся создавать свои собственные классы.
Функции, которым не нужно ничего знать о конкретном объекте называют статическими и обозначают ключевым словом static. Например, функции valueOf нужно знать число, из которого при вызове будет сделана новая строка, а вот исходная строчка просто не нужна и не уместна. Поэтому прототип этой функции будет выглядеть так:
static String valueOf (double number);
Слово static означает «статичный», то есть не меняющий. Например, в случае строк — никакая исходная строка не будет изменена, ведь она никак не участвует в вызове valueOf. Также не нужно вообще эту строку знать, поэтому её можно не указывать при вызове — вместо неё пишется просто имя класса String.
Самое главное мы уже освоили. Теперь время решать задачи. Ответьте на несколько вопросов, чтобы лучше усвоился новый материал: