您好我正在尝试编写一个将一些文本转换为定义明确的标记的类。
字符串有点类似于以下代码:(brown) "fox" 'c';
。我想得到的是(扫描仪中的一个令牌或切割后的数组我认为两者都可以正常工作)( , brown , ) , "fox" , 'c' , ;
分开(因为它们是潜在的令牌),其中包括:
'
和"
目前我正在使用扫描仪,我遇到了一些问题,分隔符无法单独给我()等,所以我现在使用了以下分隔符\s+|(?=[;\{\}\(\)]|\b)
将"
和'
作为单独的令牌以及我真的想避免它,我已经尝试为"
的变体添加一些负面的前瞻但没有运气。
我尝试过使用StreamTokenizer,但它没有保留不同的引号..
P.S。 我确实在网站上搜索并试图谷歌它,但即使有很多与扫描仪相关/正则表达式相关的问题,我找不到能解决我问题的东西。
编辑1:
到目前为止,我想出了\s+|^|(?=[;{}()])|(?<![.\-/'"])(?=\b)(?![.\-/'"])
我可能不够清楚但是什么时候
我有一些事情:
"foo";'bar')(;{
gray fox=-56565.4546;
foo boo="hello"{
我想得到:
"foo"
,;
,'bar'
,)
,(
,;
,{
gray
,fox
,=
,-56565.4546
,;
foo
,boo
,=
,"hello"
,{
但我有:
"foo"
,;'bar'
,)
,(
,;
,{
gray
,fox
,=-56565.4546
,;
foo
,boo
,="hello"
,{
请注意,当=
与其他人之间有空格时,例如:gray fox = -56565.4546;
会导致:
gray
,fox
,=
,-56565.4546
,;
我正在对上面提到的正则表达式做的是:
Scanner scanner = new Scanner(line);
scanner.useDelimiter(MY_MENTIONED_REGEX_HERE);
while (scanner.hasNext()) {
System.out.println("Got: `" + scanner.next() +"`");
//Some work here
}
答案 0 :(得分:3)
由于您正在查找可能包含小数点的所有字母数字文本,为什么不“忽略”分隔符?以下正则表达式将从输入字符串中提取带小数点块的所有字母数字。这是有效的,因为您的示例文本是:
"foo";'bar')(;{
gray fox=-56565.4546;
foo boo="hello"{
正则表达式:(?:(["']?)[-]?[a-z0-9-.]*\1|(?<=[^a-z0-9])[^a-z0-9](?=(?:[^a-z0-9]|$))|(?<=[a-z0-9"'])[^a-z0-9"'](?=(?:[^a-z0-9]|['"]|$)))
正则表达式有三条路径:
(["']?)[-]?[a-z0-9-.]*\1
捕获一个开放的引号,然后是一个减号(如果它存在),后跟一些文本或数字,这一直持续到达到收盘价。这会捕获带小数点的任何文本或数字。这些数字未经过验证,因此12.32.1
会匹配。如果您的输入文字还包含前缀为加号的数字,请将[-]
更改为[+-]
。(?<=[^a-z0-9])[^a-z0-9](?=(?:[^a-z0-9]|$))
如果前一个字符是符号,则查找非字母数字,并且此字符是符号,下一个字符也是字符串的符号或结尾,然后获取当前符号。这会捕获任何不是引号的自由浮动符号,或者像)(;{
这样的行中的多个符号。(?<=[a-z0-9"'])[^a-z0-9"'](?=(?:[^a-z0-9]|['"]|$)))
如果当前字符不是字母数字或引号,则查找字母数字或引号,并查看非字母数字,非引号或行尾。这会捕获引用之后的任何符号,这些符号不会被之前的表达式捕获,例如{
之后的"Hello"
。|
字符分隔
(["']?)[-]?[a-z0-9-.]*\1
(["']?)
["']
1到0次匹配以下字符之一:"'
[-]
1到0次匹配以下字符之一:-
[a-z0-9-.]
无限到0次匹配以下字符之一:a-z0-9-.
\1
匹配BackRef 1 (?<=[^a-z0-9])[^a-z0-9](?=(?:[^a-z0-9]|$))
(?<=[^a-z0-9])
正面LookBehind [^a-z0-9]
匹配除a-z0-9
[^a-z0-9]
匹配除a-z0-9
(?=(?:[^a-z0-9]|$))
正面LookAhead,每个子替代品都由一个或|
字符分隔(?:[^a-z0-9]|$)
[^a-z0-9]
[^a-z0-9]
匹配除a-z0-9
(?<=[a-z0-9"'])[^a-z0-9"'](?=(?:[^a-z0-9]|['"]|$))
(?<=[a-z0-9"'])
正面LookBehind [a-z0-9"']
匹配以下字符之一:a-z0-9"'
[^a-z0-9"']
匹配除a-z0-9"'
(?=(?:[^a-z0-9]|['"]|$))
正面LookAhead,每个子替代品都由一个或|
字符分隔(?:[^a-z0-9]|['"]|$)
[^a-z0-9]
[^a-z0-9]
匹配除a-z0-9
['"]
['"]
匹配以下字符之一:'"
)
结束非群组捕获声明组0获取整个匹配的字符串,而组1获取引用分隔符(如果存在)以确保它与匹配的引号匹配。
注意数组中的一些空值来自新行字符,有些是从表达式中引入的。您可以应用表达式和一些基本逻辑来确保输出数组只有非空值。
import java.util.regex.Pattern;
import java.util.regex.Matcher;
class Module1{
public static void main(String[] asd){
String sourcestring = "\"foo\";'bar')(;{
gray fox=-56565.4546;
foo boo=\"hello\"{";
Pattern re = Pattern.compile("(?:(["']?)[-]?[a-z0-9-.]*\1|(?<=[^a-z0-9])[^a-z0-9](?=(?:[^a-z0-9]|$))|(?<=[a-z0-9"'])[^a-z0-9"'](?=(?:[^a-z0-9]|['"]|$)))",Pattern.CASE_INSENSITIVE);
Matcher m = re.matcher(sourcestring);
int mIdx = 0;
while (m.find()){
for( int groupIdx = 0; groupIdx < m.groupCount()+1; groupIdx++ ){
System.out.println( "[" + mIdx + "][" + groupIdx + "] = " + m.group(groupIdx));
}
mIdx++;
}
}
}
$matches Array:
(
[0] => Array
(
[0] => "foo"
[1] =>
[2] => ;
[3] => 'bar'
[4] =>
[5] => )
[6] =>
[7] => (
[8] =>
[9] => ;
[10] =>
[11] => {
[12] =>
[13] =>
[14] =>
[15] => gray
[16] =>
[17] => fox
[18] =>
[19] => =
[20] => -56565.4546
[21] =>
[22] => ;
[23] =>
[24] =>
[25] =>
[26] => foo
[27] =>
[28] => boo
[29] =>
[30] => =
[31] => "hello"
[32] =>
[33] => {
[34] =>
)
[1] => Array
(
[0] => "
[1] =>
[2] =>
[3] => '
[4] =>
[5] =>
[6] =>
[7] =>
[8] =>
[9] =>
[10] =>
[11] =>
[12] =>
[13] =>
[14] =>
[15] =>
[16] =>
[17] =>
[18] =>
[19] =>
[20] =>
[21] =>
[22] =>
[23] =>
[24] =>
[25] =>
[26] =>
[27] =>
[28] =>
[29] =>
[30] =>
[31] => "
[32] =>
[33] =>
[34] =>
)
)
答案 1 :(得分:1)
这个想法是从特定情况开始到一般情况。试试这个表达式:
Java string:
"([\"'])(?:[^\"']+|(?!\\1)[\"'])*\\1|\\|\\||<=|&&|[()\\[\\]{};=#]|[\\w.-]+"
Raw pattern:
(["'])(?:[^"']+|(?!\1)["'])*\1|\|\||<=|&&|[()\[\]{};=#]|[\w.-]+
此处的目标不是使用hypotetic分隔符进行拆分,而是逐个实体匹配。请注意,替代顺序定义了优先级(您不能在=
之前放置=>
)
新规范的示例(需要导入Pattern&amp; Matcher):
String s = "(brown) \"fox\" 'c';foo bar || 55.555;\"foo\";'bar')(;{ gray fox=-56565.4546; foo boo=\"hello\"{";
Pattern p = Pattern.compile("([\"'])(?:[^\"']+|(?!\\1)[\"'])*\\1|\\|\\||<=|&&|[()\\[\\]{};=#]|[\\w.-]+");
Matcher m = p.matcher(s) ;
while (m.find()) {
System.out.println("item = `" + m.group() + "`");
}
答案 2 :(得分:0)
你的问题很大程度上是你试图用一个正则表达式做太多,因此无法理解该部分的相互作用。作为人类,我们都有这个麻烦。
您正在做的事情在编译器业务中有一个标准处理,称为“lexing”。词法分析器生成器接受您感兴趣的每个单个标记的正则表达式,并构建一组复杂的状态,如果它们是可区分的,将挑选出单个词位。每个令牌单独的词汇定义使得它们易于单独编写并且不会令人困惑。词法分析器使识别所有成员变得“简单”和高效。 (如果要定义包含特定引号的词法,则很容易做到这一点。)
查看广泛使用的任何解析器生成器;它们都包括lexing引擎,例如JCup,ANTLR,JavaCC,......
答案 3 :(得分:0)
也许使用像JFLex这样的扫描仪生成器,实现目标比使用正则表达式更容易。
即使您更喜欢手动编写代码,我认为将其结构化得更好一些。一个简单的解决方案是创建单独的方法,尝试从文本中“消耗”您想要识别的不同类型的标记。每种这样的方法都可以判断它是否成功。这样你就有了几个较小的代码块,可以用于不同的令牌,而不仅仅是一段难以理解和编写的大代码。