【问题标题】:Java regex for identifiers (letters, digits and underscores)用于标识符(字母、数字和下划线)的 Java 正则表达式
【发布时间】:2016-02-23 13:13:42
【问题描述】:

假设您给出的输入可能类似于 (identifier1 identifier_2 23 4)

我想在每个标识符后添加一个# 符号,它可以包含字母、数字和下划线。它们只能以字母开头,后跟字母、数字和下划线的变体。我的方法是这样的:

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

但是,这也会在我想排除的每个数字后面加上 # 符号。结果应该是(identifier1# identifier_2# 23 4)。有没有可能用正则表达式解决这个问题?

【问题讨论】:

  • 不是work as expected吗?你的意思是,# 不应该出现在 234 之后?
  • 我只想将# 符号放在标识符之后而不是数字之后。所以应该是 (identifier1# identifier_2# 23 4)
  • 我认为\b(?!\d+\b)[A-Za-z0-9_]+\b 可以提供帮助。但它不会排除像_____ 这样的字符串。要排除硫糖,您可以使用\b(?!_+\b|\d+\b)[A-Za-z0-9_]+\b 进一步限制。甚至\b(?!\d+\b)[A-Za-z0-9]+(?:_[A-Za-z0-9])*\b.
  • 我假设括号不是您输入的一部分 - 如果是,则需要额外的规则。

标签: java regex string


【解决方案1】:

更新 2

Incremental Java 说:

  • 每个标识符必须至少包含一个字符。
  • 第一个字符必须选自:字母、下划线或美元符号。第一个字符不能是数字。
  • 其余字符(第一个除外)可以来自:字母、数字、下划线或美元符号。换句话说,它可以是任何有效的标识符字符。

    简而言之,标识符是从字母、数字、下划线或美元符号中选择的一个或多个字符。唯一的限制是第一个字符不能是数字。

所以,你最好使用

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

the regex demo

更新

累加。到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

旧答案

您可以使用以下模式:

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

【讨论】:

  • 对于所需的内容,该表达式似乎相当复杂。 (?i)[a-z_]\w* 应该足够了(或在其他答案/cmets 中发布的等效项)。
  • 不知道到底需要什么。我建议替代方案。输入是否应该以_ 结尾?我也建议解决这个问题。
  • 但是,如果两个正则表达式是等价的,那么应该首选最短的,或者最容易理解的。
  • 它们不等价。
  • 不,他们不是,但可能实现了相同的目标。如果一开始对[a-zA-Z] 的要求已经排除了该选项,为什么还要检查它是否是一个数字?
【解决方案2】:

你当前的正则表达式说

一个或多个大写或小写字母、数字或下划线,在 无论顺序。

根据该正则表达式,54 是一个有效的标识符。

你真的想写

一个字母,后跟任意数量的字母、数字或 下划线,以任意顺序

那会写成这样的代码:

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

Wiktor 指出,此正则表达式仍将匹配非标识符内部的“标识符”。为了解决这个问题,您可以使用以下变体:

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

这拒绝将123ab123 作为有效标识符,但在123 ab123 中接受ab123

【讨论】:

  • 这将匹配A______。是否允许?此外,此正则表达式将匹配 A_B 内的 %%%%%%%A_B^^^^^。或者它会在34z456,,,中找到z456
  • 根据 OP 的帖子,是的:“以字母开头,后跟字母、数字和下划线的变体”
  • 不,如您所见,如果字符串以数字开头,它甚至会找到匹配项。任何东西。
  • Wiktor 就在这里,需要单词边界或其他分隔符来删除这些情况。
  • 它将匹配_________________ 字符串。它是一个有效的标识符吗?
猜你喜欢
  • 2010-09-25
  • 2015-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多