提供一些背景信息:我最近开始和一群朋友一起玩“龙与地下城”。我决定尝试制作一个允许我按级别,魔法学校等方式搜索法术的程序。为此,我拿了一个文本文件,其中包含每个法术及其信息按字母顺序列出的拼写名称,并创建了一个很少有正则表达式来对它进行排序。我终于得到它给我每个属性的正确结果。但是一旦我把它放在循环中以便立即获取所有内容,我会得到一长串错误,从StackOverflowError开始。据我所知,当你得到无限循环时,这应该会发生,但我的确无法终止。此外,我可以手动进一步循环(使用循环检查我在每个循环结束时使用键盘设置的布尔值),而不是使用简单的for或while循环。
我正在使用的代码如下。我没有包括Spell类,因为它只是标准的getter / setter和变量声明。我所拥有的学校类型只是八所学校的一个校友。
Map<String, Spell> allSpells = new HashMap<String, Spell>();
ArrayList<Spell> spellArray = new ArrayList<Spell>();
int finalLevel;
int lastMatch = 0;
int startIndex = 0;
Matcher match;
String finalTitle;
Spell.School finalSchool;
String finalDescription;
String fullList;
String titleString = ".+:\\n"; //Finds the titles of spells
Pattern titlePattern = Pattern.compile(titleString);
String levelString = "\\d\\w+-level"; //Finds the level of spells
Pattern levelPattern = Pattern.compile(levelString);
String schoolString = "(C|c)onjuration|(A|a)bjuration|(E|e)nchantment|(N|n)ecromancy|(E|e)vocation|(D|d)ivination|(I|i)llusion|(T|t)ransmutation"; //Finds the school of spells
Pattern schoolPattern = Pattern.compile(schoolString);
String ritualString = "\\(ritual\\)"; //Finds if a spell is a ritual
Pattern ritualPattern = Pattern.compile(ritualString);
String descriptionString = "\nCasting Time: (.|\\n)+?(\\n\\n)"; //Finds the description of spells
Pattern descriptionPattern = Pattern.compile(descriptionString);
try
{
BufferedReader in = new BufferedReader(new FileReader("Spell List.txt"));
// buffer for storing file contents in memory
StringBuffer stringBuffer = new StringBuffer("");
// for reading one line
String line = null;
// keep reading till readLine returns null
while ((line = in.readLine()) != null)
{
// keep appending last line read to buffer
stringBuffer.append(line + "\n");
}
fullList = stringBuffer.toString(); //Convert stringBuffer to a normal String. Used for setting fullList = a substring
boolean cont = true;
for(int i = 0; i < 100; i++) //This does not need to be set to 100. This is just a temporary number. Anything over 4 gives me this error, but under 4 I am fine.
{
//Spell Title
match = titlePattern.matcher(fullList);
match.find(); //Makes match point to the first title found
finalTitle = match.group().substring(0, match.group().length()-1); //finalTitle is set to found group, without the newline at the end
allSpells.put(finalTitle, new Spell()); //Creates unnamed Spell object tied to the matched title in the allSpells map
spellArray.add(allSpells.get(finalTitle)); //Adds the unnamed Spell object to a list.
//To be used for iterating through all Spells to find properties matching criteria
//Spell Level
match = levelPattern.matcher(fullList.substring(match.end(), match.end()+50)); //Gives an approximate region in which this could appear
if(match.find()) //Accounts for cantrips. If no match for a level is found, it is set to 0
{
finalLevel = Integer.valueOf(match.group().substring(0, 1));
}
else
{
finalLevel = 0;
}
allSpells.get(finalTitle).setSpellLevel(finalLevel);
//Spell School
match = schoolPattern.matcher(fullList);
match.find();
finalSchool = Spell.School.valueOf(match.group().substring(0, 1).toUpperCase() + match.group().substring(1, match.group().length())); //Capitalizes matched school
allSpells.get(finalTitle).setSpellSchool(finalSchool);
//Ritual?
match = ritualPattern.matcher(fullList.substring(0, 75));
if(match.find())
{
allSpells.get(finalTitle).setRitual(true);
}
else
allSpells.get(finalTitle).setRitual(false);
//Spell Description
match = descriptionPattern.matcher(fullList);
match.find();
finalDescription = match.group().substring(1); //Gets rid of the \n at the beginning of the description
allSpells.get(finalTitle).setDescription(finalDescription);
lastMatch = match.end();
System.out.println(finalTitle);
fullList = fullList.substring(lastMatch);
}
}
catch (Exception e)
{
e.printStackTrace();
}
如果有帮助,我有我正在使用的列表here。 正如我在代码的注释中提到的,通过循环超过4次给了我这个错误,但是在4下没有。我也尝试过这样做一个while循环,我得到了同样的错误。
我曾尝试在线搜索解决方案,但我看到的有关此错误的所有信息都只是谈到了递归调用。如果有人有解决方案,我会非常感激。感谢。
编辑:我收到的错误列表很大,所以我把它放在一个文本文件中here 。我知道人们要求堆栈跟踪,我希望这就是他们的意思。我还是比较新的java,从来没有使用堆栈跟踪。
编辑2:我发现如果我只是用“\ nCast Time:”替换描述正则表达式,它会在整个事情中运行而没有错误。当然,唯一的问题是它没有收集我想要的所有信息。希望这些信息有助于确定问题。
最终编辑:一旦找到导致问题的特定行,我做了一些搜索,发现增加堆栈大小解决了问题。
答案 0 :(得分:0)
通过增加堆栈大小,您正在处理症状并使问题得不到解决。在这种情况下,问题是效率低下的正则表达式。
首先,如果你想匹配任何包括换行符,你应该总是使用DOTALL选项。像.|\n
这样的替代效率要低得多。 (它也是不正确的。点匹配任何不是line terminator的东西,这可能远远超过\n
。)
其次,该替换是在捕获组内部,量化器位于组外:(.|\n)+?
。这意味着你一次捕获一个角色,只用下一个角色覆盖捕获的角色,依此类推。你正在使正则表达式引擎做了很多不必要的工作。
这是我要使用的正则表达式:
"(?ms)^Casting Time: (.+?)\n\n"
可以使用内联修饰符(?s)
激活DOTALL选项。我还使用了MULTILINE选项,它允许我使用^
将匹配锚定到行的开头。这样,就没有必要消耗领先的\n
,只是稍后将其删除。实际上,如果您使用group(1)
代替group()
,则也会排除尾随\n\n
。
对于RegExr,它使用与Java不同的正则表达式 - 一个功能少得多的一个。大多数Java正则表达式都适用于选择了pcre (php)
选项的优秀Regex101站点。为了绝对兼容,请使用RegexPlanet的Java page或代码测试网站Ideone。