2016-02-23 6 views
1

Предположим, вы указали ввод, который может выглядеть следующим образом: (identifier1 identifier_2 23 4).Java regex для идентификаторов (буквы, цифры и символы подчеркивания)

Я хочу добавить символ # после каждого идентификатора, который может содержать буквы, цифры и символы подчеркивания. Они могут начинаться только с буквы, сопровождаемой вариациями букв, цифр и символов подчеркивания. Мой подход был что-то вроде этого:

input.replaceAll("[A-Za-z0-9_]+", "$0#"); 

Однако это также ставит # символы после каждой цифры, которые я хотел исключить. Результат должен быть (identifier1# identifier_2# 23 4). Можно ли решить эту проблему с помощью регулярного выражения?

+0

Не так ли [работа, как и ожидалось] (https://regex101.com/r/bL7kJ8/1)? Вы имеете в виду, что '' 'должно появляться после' 23' и '4'? –

+0

Я только хочу поместить символы '#' после идентификаторов, но не после цифр. Так что это должно быть (identifier1 # identifier_2 # 23 4) –

+0

Думаю '\ b (?! \ D + \ b) [A-Za-z0-9 _] + \ b' может помочь. Но это не исключает строки, такие как '_____'. Чтобы исключить thiose, вы можете дополнительно ограничить '\ b (?! _ + \ B | \ d + \ b) [A-Za-z0-9 _] + \ b'. Или даже ['\ b (?! \ D + \ b) [A-Za-z0-9] + (?: _ [A-Za-z0-9]) * \ b'] (https: // regex101. ком/г/bL7kJ8/2). –

ответ

3

Ваше текущее регулярное выражение говорит

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

В соответствии с этим регулярным выражением 54 является допустимым идентификатором.

Вы на самом деле хотели написать

письмо, за которым следует любое количество букв, цифр или подчеркивания, в любом порядке

Это было бы написано в коде, как:

input.replaceAll("[A-Za-z][A-Za-z0-9_]*", "$0#"); 

Wiktor отмечает, что это повторно gex по-прежнему будет соответствовать «идентификаторам», которые находятся внутри того, что не является идентификатором-иш. Чтобы решить эту проблему, вы можете использовать следующий вариант:

input.replaceAll("\\b([A-Za-z][A-Za-z0-9_]*)\\b", "$1#") 

Это отторгает 123ab123 как действительный идентификатор, но принимает ab123 в 123 ab123

+1

Это будет соответствовать 'A ______'. Это разрешено? Кроме того, это регулярное выражение будет соответствовать 'A_B' внутри' %%%%%%%% A_B ^^^^^ '. Или он найдет 'z456' в' 34z456 ,,, ' –

+0

Согласно сообщению OP, да:« начните с буквы, за которой следуют варианты букв, цифр и символов подчеркивания » – tucuxi

+1

Нет, как вы видите, она даже найдет если строка начинается с цифры. Что-нибудь. –

2

UPDATE 2

Incremental Java говорит:

  • Каждый идентификатор должен иметь хотя бы один символ.
  • Первый символ должен быть выбран из: альфы, подчеркивания или знака доллара. Первый символ не может быть цифрой.
  • Остальные персонажи (помимо первого) могут быть: альфа, цифра, знак подчеркивания или знак доллара. Другими словами, это может быть любой действительный символ идентификатора.

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

Таким образом, вы бы лучше использовать

String pattern = "(?:\\b[_a-zA-Z]|\\B\\$)[_$a-zA-Z0-9]*+"; 

См the regex demo

UPDATE

АСС. до Representing identifiers using Regular Expression, регулярное выражение идентификатора - [_a-zA-Z][_a-zA-Z0-9]*.

Таким образом, вы можете использовать

String pattern = "\\b[_a-zA-Z][_a-zA-Z0-9]*\\b"; 

ПРИМЕЧАНИЕ, что позволяет _______.

Вы можете использовать

String p = "\\b_*[a-zA-Z][_a-zA-Z0-9]*\\b"; 

Чтобы избежать этого. См. IDEONE demo.

String s = "(identifier1 identifier_2 23 4) ____ 33"; 
String p = "\\b_*[a-zA-Z][_a-zA-Z0-9]*\\b"; 
System.out.println(s.replaceAll(p, "$0#")); 

Выход: (identifier1# identifier_2# 23 4) ____ 33

OLD ОТВЕТ

Вы можете использовать следующую схему:

String p = "\\b(?!\\d+\\b)[A-Za-z0-9]+(?:_[A-Za-z0-9]+)*\\b"; 

Или (если _ может появиться в конце):

String p = "\\b(?!\\d+\\b)[A-Za-z0-9]+(?:_[A-Za-z0-9]*)*\\b"; 

См regex demo

Схема требует, чтобы все слово (как выражение заключено с границами слова \b) не должен быть равно числу (проверено с (?!\d+\b)) и развернутыми частями [A-Za-z0-9]+(?:_[A-Za-z0-9])* матчей без подчеркивания которые сопровождаются нулем или несколькими последовательностями подчеркивания, за которыми следуют несимвольные словарные фрагменты символов.

IDEONE demo:

String s = "(identifier1 identifier_2 23 4) ____ 33"; 
String p = "\\b(?!\\d+\\b)[A-Za-z0-9]+(?:_[A-Za-z0-9]*)*\\b"; 
System.out.println(s.replaceAll(p, "$0#")); 

Выход: (identifier1# identifier_2# 23 4) ____ 33

+1

Это выражение кажется довольно сложным для того, что требуется. '(? i) [a-z _] \ w *' должно быть достаточно (или эквивалентов, как указано в других ответах/комментариях). – Thomas

+0

Не знаю, что именно требуется. Я предлагаю альтернативы. Если вход заканчивается на '_' или нет? Я также предлагаю решение. –

+0

Однако, если два регулярных выражения эквивалентны, то предпочтительнее кратчайший или наиболее понятный. – tucuxi

Смежные вопросы