Доброго времени суток!
Чтобы выполнить в данной задаче условие: "...слова, которые содержат цифры", ничего умнее не придумал, как две регулярки и таким образом исключил "только" цифры:
\w+\d+\w*\p{Punct}? - пропускает вариант, когда нет символов после цифр
\w*\d+\w+\p{Punct}? - пропускает вариант, когда нет символов до цифр
(до кучи добавил проверку на пунктуацию в конце слова, в данном случае никакой роли не играет)
Валидатор пропустил. В комментариях прочитал, что можно было и не заморачиваться, Валидатор принимает и только цифры.
Но остался вопрос: можно ли объединить два выражения в одной регулярке так, чтобы они проверялись отдельно друг от друга?
например:
Pattern p = Pattern.compile("ВЫРАЖЕНИЕ1" ИЛИ "ВЫРАЖЕНИЕ2");
соответственно p.matcher(words).find() выдаст true, если хотя бы одно выражение сработает?
VladSL
27 уровень
Регулярка. Как включить логику "ИЛИ" в одном регулярном выражении для ДВУХ условий
Решен
Комментарии (43)
- популярные
- новые
- старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
VladSL
11 ноября 2019, 09:30
Всем огромное спасибо!
Низкий поклон vk!
Узнал про "исключаемую группу"! В копилку!
0
hidden #598481
11 ноября 2019, 09:40
Пожалуйста, рад помочь!
К слову, правильный ответ на вопрос в заголовке дала Ксения, и регулярки альтернативятся через пайп |
Если все это интересно, читай javadoc по паттернам, там еще много интересного.
0
VladSL
11 ноября 2019, 09:46
В доки сразу полез. Но так и не понял, почему вот это не сработало:
String s = "123 12asdf asdf12 as12df";
String[] strings = s.split(" ");
Pattern p1 = Pattern.compile("\\D*\\d+\\D+ | \\D+\\d+\\D*");
for (int i = 0; i < strings.length; i++) {
if (p1.matcher(strings[i]).find()){
System.out.println(strings[i]);
}
}
Выдает пустоту...
0
IceBergMaster
11 ноября 2019, 09:54решение
У тебя же там пробелы стоят.
+2
hidden #598481
11 ноября 2019, 10:00
ну и кроме пробелов надо понимать, что \D - это не тоже самое, что и "символы \w кроме \d", это вот прямо все-все-все кроме цифр, т.е. и пробелы, и знаки препинания, переносы, таблуяции - оно все входит в \D т.к. не является цифрами.
0
IceBergMaster
11 ноября 2019, 10:01
Ну так я потому и спрашиваю, каким там образом могут оказаться пробелы?
0
hidden #598481
11 ноября 2019, 10:02
Пробелы, которыми ты обрамляешь пайп в середине регулярки: " | " - это не декоративные пробелы, чтобы выделить "палку", это именно символы пробела. Т.е. ты говоришь "или левая регулярка, заканчивающаяся на пробел, или правая регулярка, начинающаяся с пробела"
0
VladSL
11 ноября 2019, 10:03
о как. об этом не подумал...
0
hidden #598481
11 ноября 2019, 10:04
внутри регулярки каждый символ имеет смысл паттерна
0
VladSL
11 ноября 2019, 10:05
Мой косяк... Век живи, век учись))) И тебе низкий поклон!!!
0
hidden #598481
11 ноября 2019, 10:05
да брось кланяться, тут все учатся)
0
Ksenia VolkovaJava Developer в DXCMaster
11 ноября 2019, 10:06
Отличный вопрос вышел - куча полезной информации выплыла ))
+2
VladSL
11 ноября 2019, 10:07
Спина не переломится, она тренированная) А людям приятно)))
0
Ksenia VolkovaJava Developer в DXCMaster
11 ноября 2019, 06:05полезный
Оператор |
+1
VladSL
11 ноября 2019, 06:52
Пробовал. Результат - пустой файл.
0
Ksenia VolkovaJava Developer в DXCMaster
11 ноября 2019, 07:02
Покажи код.
| должно быть внутри регулярки.
То есть не "выражение1" | "выражение2", а "(выражение1)|(выражение2)"
0
VladSL
11 ноября 2019, 07:15
Ксения, тайм-аут. Пока набивал "тестовый" код, выяснил что цифры-то как раз проходят... И, кстати, скобки не пробовал). Запутался, пошёл распутываться
0
VladSL
11 ноября 2019, 07:25
Пример1 (в консоль ничего не вышло, скобки тоже не помогают):
String s = "123 12asdf asdf12 as12df";
String[] strings = s.split(" ");
Pattern p1 = Pattern.compile("\\D*\\d+\\D+ | \\D+\\d+\\D*");
for (int i = 0; i < strings.length; i++) {
if (p1.matcher(strings[i]).find()){
System.out.println(strings[i]);
}
}
0
VladSL
11 ноября 2019, 07:26
Пример 2:
String s = "123 12asdf asdf12 as12df";
String[] strings = s.split(" ");
Pattern p1 = Pattern.compile("\\D*\\d+\\D+");
Pattern p2 = Pattern.compile("\\D+\\d+\\D*");
for (int i = 0; i < strings.length; i++) {
if (p1.matcher(strings[i]).find() || p2.matcher(strings[i]).find()){
System.out.println(strings[i]);
}
}
В консоли:
12asdf
asdf12
as12df
0
VladSL
11 ноября 2019, 07:30
С двумя "||" тоже не то. Выводит всё, даже только цифры.
0
Ksenia VolkovaJava Developer в DXCMaster
11 ноября 2019, 07:30
"\\D*\\d+\\D+ \\| \\D+\\d+\\D*"
Экранирование \\|
0
VladSL
11 ноября 2019, 07:31
с экранами тоже пусто)
Да вроде как "|" и не нужно экранировать...Не прав?
0
Ksenia VolkovaJava Developer в DXCMaster
11 ноября 2019, 07:35
Все служебные символы вроде нужно экранировать.
"[\\D*\\d+\\D+\\|\\D+\\d+\\D*]"
Возможно со скобками можно поэкспериментировать
0
Wladyslaw Java Developer Master
11 ноября 2019, 08:06
Если я правильно понимаю условие - все что разделено пробелами - мы в праве считать словами.
Так почему бы просто не проверить есть ли в "слове" хоть одна цифра да и все?
Че-то ты усложняешь, как по мне.
+2
VladSL
11 ноября 2019, 08:09
Согласен, Владислав. Так большинство и сделало. Я действительно усложнил задачу, но отсюда и вопрос - а если бы надо было исключить цифры?
0
Wladyslaw Java Developer Master
11 ноября 2019, 08:15
Как-то так? Не до конца тебя понимаю
Хочешь найти только слова которые полностью из цифр состоят?
Если под "исключить цифры" имеются ввиду только слова без единой цифры - ну так можно тогда, например
0
YuriyExpert
11 ноября 2019, 08:33
| не нужно экранировать.
0
YuriyExpert
11 ноября 2019, 08:37
Если надо исключить цифры, то достаточно проверить что цифр в слове нет.
По условию задачи слова разделены подин пробелом, т.е. в строке "word, word" 2 слова: "word," и "word". Т.е. можно разбить строку на слова split-ом, а для каждого слова проверить есть ли в нем хотя бы один символ являющийся цифрой.
0
VladSL
11 ноября 2019, 08:45
Допустим, есть строка:
String s = "123 12asdf asdf12 as12df";
Надо, чтобы в консоль вывело все слова, в которых есть цифра, НО исключая ТОЛЬКО цифры, т.е. вывод:
12asdf
asdf12
as12df
Выше я писал код, который выдаёт результат, но... там через 2 паттерна и в if условие, которое проверяет на соответствие тому или иному паттерну.
Вот и подумал, можно ли создать один паттерн с одной регуляркой, в котором бы реализовалась логика "или" из if.
Похоже, мне надо учиться еще и проблемы свои объяснять...
0
VladSL
11 ноября 2019, 08:49
Юрий, в том то и задача: получается всё равно две проверки. Сначала я проверяю, есть ли слова с цифрами (их надо вывести), а потом еще проверяю, есть ли слова только из цифр, чтобы их исключить из вывода. А хотелось бы через один паттерн... )))
0
hidden #598481
11 ноября 2019, 08:49
Задание не требует "исключать ТОЛЬКО цифры". Число - это тоже "слово, содержащее цифры", частный его случай.
0
VladSL
11 ноября 2019, 08:50
vk, согласен.... Также как и с Владиславом:
"Согласен, Владислав. Так большинство и сделало. Я действительно усложнил задачу, но отсюда и вопрос - а если бы надо было исключить цифры?"
)))
0
YuriyExpert
11 ноября 2019, 08:53
Где Вы в условии видите требование что-то исключить? оО
0
Wladyslaw Java Developer Master
11 ноября 2019, 08:54
Как-то так?
Или что-то такого рода
0
hidden #598481
11 ноября 2019, 08:55
Так?
0
VladSL
11 ноября 2019, 08:58
Я действительно усложнил задачу, но отсюда и вопрос - а если бы надо было исключить цифры?
0
VladSL
11 ноября 2019, 09:02
vk, поменял лишь source и ... выдало цифры)))
String s = "123 12asdf asdf12 as12df";
Matcher matcher = Pattern.compile("\\w*\\d+\\w+|\\w+\\d+\\w*").matcher(s);
StringJoiner joiner = new StringJoiner(" ");
while (matcher.find()) {
joiner.add(matcher.group());
}
String result = joiner.toString();
System.out.println(result);
А цифры нам не нужны...)
0
YuriyExpert
11 ноября 2019, 09:09полезный
Есть варианты сделать это одной регуляркой, но с точки зрения простоты восприятия и читаемости кода все же в таком случае было бы лучше сделать две вложенных проверки - первая на наличие хотя бы одной цифры, вторая - на наличие хотя бы одного символа не являющегося цифрой.
+1
hidden #598481
11 ноября 2019, 09:20решение
Согласен, просчитался.
Тогда вот такая нечитаемая регулярка:
Читается так: вхождение соответствующее \b\w*\d+\w*\b
и при этом не соответствующее \b\d+\b
Жирным выделил "материальные" символы.
\b обозначает границу слова, соответственно вхождения между двумя \b соответствуют либо только whitespace символам, либо наоборот только словесным символам. Поскольку между ними есть \d+, то вариант с whitespace символами отпадает, остаются только словесные вхождения.
И поскольку мы исключаем вхождения, где только \d+, используя исключаемую группу (?!), то \w* в основной группе будет обозначать обязательное наличие буквы или "_".
+2
hidden #598481
11 ноября 2019, 09:27полезный
сам бы я решал проще, сделал бы сплит по пробелам, и каждый элемент массива проверил бы на matches(".*\\d.*"), и отобранные слова включил в итоговый результат
+1
VladSL
11 ноября 2019, 09:28
Юрий, согласен, насчет читаемости.
vk, похоже сработало!!! Жму руку!
Читается, действительно, тяжеловато. Видимо, лучше так не делать)
0
IceBergMaster
11 ноября 2019, 10:09
Спецсимволы регулярок наоборот не нужно экранировать, иначе они превратятся в обычные символы, исключение - это метасимволы состоящие из слеша и дополнительного символа, они конфликтуют с обычным назначением слеша в java, который используют для указания управляющих последовательностей.
\b в строке и \b в регулярке(\\b) - это очень разные вещи.
0
Ksenia VolkovaJava Developer в DXCMaster
11 ноября 2019, 10:15
Да, точно. Экранировать нужно как раз для того, чтобы спецсимволы не воспринимались как спецсимволы.
0