I have the following code:
#SuppressWarnings("resource")
public void changeSkin(String name){
try {
URL uuidURL = new URL("https://api.mojang.com/users/profiles/minecraft/" + name);
String uuid = new Scanner(uuidURL.openStream(), "UTF-8").useDelimiter("\\A").next();
uuid = uuid.substring(7, 39);
System.out.println(uuid); // works
URL valueURL = new URL("https://sessionserver.mojang.com/session/minecraft/profile/" + uuid + "?unsigned=false");
String value = new Scanner(valueURL.openStream(), "UTF-8").useDelimiter("\\A").next();
value = value.replace('"', '!');
value = value.replaceAll("!value!:!", "*");
value = value.replaceAll("=!,", "+");
value = value.substring(value.charAt('*'), value.charAt('+')); // Gives an error outOfBounds: -13
String signature = new Scanner(valueURL.openStream(), "UTF-8").useDelimiter("\\A").next();
signature = signature.replaceAll("!signature!:!", "_");
signature = signature.replaceAll("=!}]}", "~");
signature = signature.substring(value.charAt('_'), value.charAt('~'));
System.out.println(signature);
System.out.println(value);
//profile.getProperties().put("textures", new Property(value, signature));
} catch (Exception e) {
e.printStackTrace();
}
}
While running it throws and outOfBoundsException: -13
But how can that throw a negative number?
Thanks for any help
Edit: Here is the website: https://sessionserver.mojang.com/session/minecraft/profile/e96ca9800c6c4a1588a2922a02ae1080?unsigned=false
I guess you are making some kind of minecraft bot or something ... but that's irrelevant.
You are using charAt incorrectly.
https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#charAt(int)
What you are looking for is indexOf
https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#indexOf(int)
You ask for the character position for '*' and THEN ask for the position '+'. The problem is that the plus is located BEFORE the star in the string, so it's returning a negative number.
To remedy, I would suggest breaking the substring into two lines:
value = value.substring(value.indexOf('*'));
value = value.substring(0, value.indexOf('+'));
Though it may seem irrelevant, breaking it into two lines breaks the string at the first instance of the * and then at the NEXT first instance of the +.
Related
I'm a writing a parser that will extract the tag and value out of a line that it reads from a file and I want to know how to get the value. So in this case I want to get
key = "accountName" and
value = "fname LName" and have it repeat with each line.
<accountName>fname LName</accountName>
<accountNumber>12345678912</accountNumber>
<accountOpenedDate>20200218</accountOpenedDate>
This is my code, this is within a while loop that is scanning each line using bufferedReader. I managed to get the key properly, but when I try to get the value, I get "String index out of range - 12. Not sure how to get the value between the two arrows > <.
String line;
if(line.startsWith("<"){
key = line.substring(line.indexOf("<"+1, line.indexOf(">"));
value = line.substring(line.indexOf(">"+1, line.indexOf("<")+1);
}
Though it is recommended to use XML parser but still if you want to do it by manually processing the string at each line:
(using regular expression is recommended to process line) but if you want todo manually with substring way here is the example:
private static void readKeyValue(String line) {
String key = null;
String value = null;
if (null != line && line.startsWith("<") && line.contains("</")) {
key = line.substring(line.indexOf("</")+ 2 , line.lastIndexOf(">"));
value = line.substring(line.indexOf(">") + 1, line.indexOf("</"));
}
System.out.println("key: "+ key);
System.out.println("value: "+ value);
}
You can use regular expressions to extract, assuming the line variable is a string read from each line.
String pattern = "<([a-zA-Z]+.*?)>([\\s\\S]*?)</[a-zA-Z]*?>";
// Create a Pattern object
Pattern r = Pattern.compile(pattern);
// Now create matcher object.
Matcher m = r.matcher(line);
// find
if (m.find()) {
String key = m.group(1);
String value = m.group(2);
System.out.println("Key: " + key);
System.out.println("Value: " + value);
} else {
System.out.println("Invalid");
}
Hi, you can see my code below. I have some strings Country, rank and grank in my code, initially they will be null, but if regex is mached, it should change the value. But even if regex is matched it is not changing the value it is always null. If I remove all if statements and append the string it works fine, but if match is not found it is throwing an exception. Please let me know how can I check this in if logic.
System.err.println(content);
Pattern c = Pattern.compile("NAME=\"(.*)\" RANK");
Pattern r = Pattern.compile("\" RANK=\"(.*)\"");
Pattern gr = Pattern.compile("\" TEXT=\"(.*)\" SOURCE");
Matcher co = c.matcher(content);
Matcher ra = r.matcher(content);
Matcher gra = gr.matcher(content);
co.find();
ra.find();
gra.find();
String country = null;
String Rank = null;
String Grank = null;
if (co.matches()) {
country = co.group(1);
}
if (ra.matches()) {
Rank = ra.group(1);
}
if (gra.matches()) {
Grank = gra.group(1);
}
You have to escape a single \ - use double \\ then it should work.
Tried this?
while (co.find()) {
System.out.print("Start index: " + co.start());
System.out.print(" End index: " + co.end() + " ");
System.out.println(co.group());
}
Personally I can't make your program work with / without the if so it's not a problem of logic but just a problem that it doesn't match the string for me
So I changed it to get something working, maybe you can use it :)
String content = "NAME=\"salut\" RANK=\"pouet\" TEXT=\"text\" SOURCE";
System.out.println(content);
System.out.println(content.replaceAll(("NAME=\"(.*)\"\\sRANK=\"(.*)\"\\sTEXT=\"(.*)\" SOURCE"), "$1---$2---$3"));
Output
NAME="salut" RANK="pouet" TEXT="text" SOURCE
salut---pouet---text
I want to parse the data below in java. What approach shall I follow?
I want to neglect ; inside { }.
Thus Version, Content, Provide, UserConfig and Icon as name and corresponding values.
Version:"1";
Content:2013091801;
Provide:"Airtel";
UserConfig :
{
Checksum = "sha1-234448e7e573b6dedd65f50a2da72245fd3b";
Source = "content\\user.ini";
};
Icon:
{
Checksum = "sha1-a99f835tytytyt3177674489770e613c89390a8c4";
Source = "content\\resept_ico.bmp";
};
Here we can't use String.split(";") function.
It would have been lot more complex to convert using the Regex and then creating a method to extract the required fields,
What I did was converted the above mentioned input to Json compatible string and then used GSON library by google to parse the String to my customized class,
class MyVer
{
String Version;
long Content;
String Provide;
Config UserConfig;
Config Icon;
String Source;
}
class Config
{
String Checksum;
String Source;
}
public static void main(String[] args)
{
String s = "Version:\"1\";Content:2013091801;Provide:\"Airtel\";UserConfig :{ Checksum = \"sha1-234448e7e573b6dedd65f50a2da72245fd3b\"; Source = \"content\\user.ini\";};Icon:{ Checksum = \"sha1-a99f835tytytyt3177674489770e613c89390a8c4\"; Source = \"content\\resept_ico.bmp\";};";
String startingBracePattern = Pattern.quote("{");
String endBracePattern = Pattern.quote("}");
s=s.replaceAll(Pattern.quote("\\"), "\\\\\\\\"); //Replacing all the single \ with double \\
s = s.replaceAll("\\s*"+startingBracePattern +"\\s*", "\\{\""); //Replacing all the `spaces { spaces` with `{"` MEANS all the { to replace with {"
s = s.replaceAll(";\\s*"+endBracePattern +"\\s*;", "\\};"); //Replacing all the `; spaces } spaces ;` with `},"` MEANS all the ;}; to replace with };
s = "{\"" + s.substring(0, s.length() - 1) +"}"; //Removing last ; and appending {" and }
s = s.replaceAll("\\s*:", "\":"); // Replacing all the `space with :` with `":`
s = s.replaceAll("\\s*;\\s*", ",\""); //Replacing all the `spaces ; spaces` with `,"`
s = s.replaceAll("\\s*=\\s*", "\":"); //Replacing all the `spaces = spaces` with `":`
Gson gson = new Gson();
MyVer newObj = gson.fromJson(s, MyVer.class);
}
This converts and give you the object of MyVer and then you can access all the variables.
NOTE: You can alter the code little to replace all \r\n if they are present in your input variables. I have not used them and your actual data supplied in question in a single line for simplicity.
JSON sounds a lot easier in this case..
.. however, if you were to do this using regular expressions, one way would be:
for the simple cases (eg. version):
// look for Version: some stuff ;
Pattern versionPattern = Pattern.compile("Version\\s*:\\s*\"\\w+\"\\s*;");
// the whole big string you're looking in
String bigString = ...; // the entire string from before can go here
// create a matcher for the "version pattern"
Matcher versionMatcher = versionPattern.matcher(bigString);
// check if there's a match in the string
if(versionMatcher.find()) {
// get the matching substring
String matchingSubstring = bigString.substring(
versionMatcher.start(),
versionMatcher.end()
);
// we need the area between the quotes
String version = matchingSubstring.split("\"")[1];
// do something with it
...
}
for the harder (multi-line) cases (eg. UserConfig):
// look for UserConfig : { some stuff };
Pattern userconfigPattern = Pattern.compile("UserConfig\\s*:\\s*{[^}]*};", Pattern.DOTALL);
// create a matcher for the "user config pattern"
Matcher userconfigMatcher = userconfigPattern.matcher(bigString);
// check if there's a match in the string
if(userconfigMatcher.find()) {
// get the matching substring
String matchingSubstring = bigString.substring(
userconfigMatcher.start(),
userconfigMatcher.end()
);
// we need the area between the curly braces
String version = matchingSubstring.split("[{}]")[1];
// do something with it
...
}
EDIT: this is probably an easier way
// split the input string into fields
String[] fields = bigString.split("[^:]+:([^{;]+;)|({[^}]+};)");
// for each key-value pair
for(String field : fields) {
// the key and value are separated by colons
String parts = field.split(":");
String key = parts[0];
String value = parts[1];
// do something with them, or add them to a map
...
}
This last way splits the input string based on the assumption that each key-value pair consists of:
some (non-colon) characters at the start, followed by
a colon,
either
-> some characters that are not curly braces or semi-colons (for simple attributes), or
-> curly braces containing some characters that are not curly braces
a semi-colon
Here is json solution
str = "{" + str.substring(0, str.lastIndexOf(";")).replace(";\n}", "}") + "}";
try {
JSONObject json = new JSONObject(str);
String version = json.getString("Version");
JSONObject config = json.getJSONObject("UserConfig");
String source = config.getString("Source");
} catch (JSONException e) {
e.printStackTrace();
}
since ";" should not be in front of "}"
Source = "content\\resept_ico.bmp";
}
we need remove them
I want to filter a string.
Basically when someone types a message, I want certain words to be filtered out, like this:
User types: hey guys lol omg -omg mkdj*Omg*ndid
I want the filter to run and:
Output: hey guys lol - mkdjndid
And I need the filtered words to be loaded from an ArrayList that contains several words to filter out. Now at the moment I am doing if(message.contains(omg)) but that doesn't work if someone types zomg or -omg or similar.
Use replaceAll with a regex built from the bad word:
message = message.replaceAll("(?i)\\b[^\\w -]*" + badWord + "[^\\w -]*\\b", "");
This passes your test case:
public static void main( String[] args ) {
List<String> badWords = Arrays.asList( "omg", "black", "white" );
String message = "hey guys lol omg -omg mkdj*Omg*ndid";
for ( String badWord : badWords ) {
message = message.replaceAll("(?i)\\b[^\\w -]*" + badWord + "[^\\w -]*\\b", "");
}
System.out.println( message );
}
try:
input.replaceAll("(\\*?)[oO][mM][gG](\\*?)", "").split(" ")
Dave gave you the answer already, but I will emphasize the statement here. You will face a problem if you implement your algorithm with a simple for-loop that just replaces the occurrence of the filtered word. As an example, if you filter the word ass in the word 'classic' and replace it with 'butt', the resultant word will be 'clbuttic' which doesn't make any sense. Thus, I would suggest using a word list,like the ones stored in Linux under /usr/share/dict/ directory, to check if the word is valid or it needs filtering.
I don't quite get what you are trying to do.
I ran into this same problem and solved it in the following way:
1) Have a google spreadsheet with all words that I want to filter out
2) Directly download the google spreadsheet into my code with the loadConfigs method (see below)
3) Replace all l33tsp33k characters with their respective alphabet letter
4) Replace all special characters but letters from the sentence
5) Run an algorithm that checks all the possible combinations of words within a string against the list efficiently, note that this part is key - you don't want to loop over your ENTIRE list every time to see if your word is in the list. In my case, I found every combination within the string input and checked it against a hashmap (O(1) runtime). This way the runtime grows relatively to the string input, not the list input.
6) Check if the word is not used in combination with a good word (e.g. bass contains *ss). This is also loaded through the spreadsheet
6) In our case we are also posting the filtered words to Slack, but you can remove that line obviously.
We are using this in our own games and it's working like a charm. Hope you guys enjoy.
https://pimdewitte.me/2016/05/28/filtering-combinations-of-bad-words-out-of-string-inputs/
public static HashMap<String, String[]> words = new HashMap<String, String[]>();
public static void loadConfigs() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(new URL("https://docs.google.com/spreadsheets/d/1hIEi2YG3ydav1E06Bzf2mQbGZ12kh2fe4ISgLg_UBuM/export?format=csv").openConnection().getInputStream()));
String line = "";
int counter = 0;
while((line = reader.readLine()) != null) {
counter++;
String[] content = null;
try {
content = line.split(",");
if(content.length == 0) {
continue;
}
String word = content[0];
String[] ignore_in_combination_with_words = new String[]{};
if(content.length > 1) {
ignore_in_combination_with_words = content[1].split("_");
}
words.put(word.replaceAll(" ", ""), ignore_in_combination_with_words);
} catch(Exception e) {
e.printStackTrace();
}
}
System.out.println("Loaded " + counter + " words to filter out");
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Iterates over a String input and checks whether a cuss word was found in a list, then checks if the word should be ignored (e.g. bass contains the word *ss).
* #param input
* #return
*/
public static ArrayList<String> badWordsFound(String input) {
if(input == null) {
return new ArrayList<>();
}
// remove leetspeak
input = input.replaceAll("1","i");
input = input.replaceAll("!","i");
input = input.replaceAll("3","e");
input = input.replaceAll("4","a");
input = input.replaceAll("#","a");
input = input.replaceAll("5","s");
input = input.replaceAll("7","t");
input = input.replaceAll("0","o");
ArrayList<String> badWords = new ArrayList<>();
input = input.toLowerCase().replaceAll("[^a-zA-Z]", "");
for(int i = 0; i < input.length(); i++) {
for(int fromIOffset = 1; fromIOffset < (input.length()+1 - i); fromIOffset++) {
String wordToCheck = input.substring(i, i + fromIOffset);
if(words.containsKey(wordToCheck)) {
// for example, if you want to say the word bass, that should be possible.
String[] ignoreCheck = words.get(wordToCheck);
boolean ignore = false;
for(int s = 0; s < ignoreCheck.length; s++ ) {
if(input.contains(ignoreCheck[s])) {
ignore = true;
break;
}
}
if(!ignore) {
badWords.add(wordToCheck);
}
}
}
}
for(String s: badWords) {
Server.getSlackManager().queue(s + " qualified as a bad word in a username");
}
return badWords;
}
I made an application in which I can get a field's value through a regular expression with the help of a matcher... I made a method in which I pass a field and get a response. In string today I got some odd behaviour in my response I got AgentId = 25001220052805950 and after matcher I got fake so I have to check whether a field whose name contains "AgentId" exists and verify the values.
Needed Fields:
SecondaryAgentId=fake; PrimaryAgentId=fake;
Responce :
IsPrimaryAgentId=true; AgentId=25001220052805950; MerchantID=19; Cashier=michael; IsManualPayment=1; UserID=GraceRose; Password=rose1234; AmountUserEntered=2; AmountApproved=0; AmountDifference=0; Amount=0; CustomerNameAttempts=0; ProductID=Agriculture; InvoiceID=inv7443; SiteUrl=http://www.thcelink.com/index.php/shoping/checkout/step/step-1; ReturnURL=http://220.2.3:2027/Customer/Thanks.aspx; ResponseType=1; PrimaryAgentId=fake; PrimaryCurrencyCode=fake; SecondaryAgentId=fake; SecondaryCurrencyCode=fake; MerchantName=GraceRose; EmailId=rr#myglobal.com; Query1Attempts=0; MerchantTransactionID=543; MerchantTransactionSequenceID=246; txtAmtIsVisible=false; isQuery1Executed=false; isQuery2Executed=false; Voucher=fake; Passcode=fake; Error=fake; QueryType=fake; Payer=fake; CurrencyName=fake; CurrencySymbol=fake; CustomerName=fake; EmailBody=fake; ErrorText=fake; CustomerEmailID=fake; NavigatePageValue=0; IsCustomerInsertSucess=false; IdType=fake; IdNumber=fake; AggregateAttempts=0; Voucher2=fake; PassCode2=fake; Voucher3=fake; PassCode3=fake; TransCode=0; TransactionDate=2012-06-11T12:04:52.921875+05:30; NumberInWords=fake; MerchantCompany=fake; InvoiceNumber=fake; OverPaidAmount=0; InsufficientAmount=0; OverPaymentForEmail=fake; RedirectPage=false;
Update::
private String GetString1(String strManualproResponce2, String paternField) {
// TODO Auto-generated method stub
String s = null;
if(paternField.equalsIgnoreCase("AgentId"))
{
Pattern pinPattern2 = Pattern.compile("^"+paternField + "=(.*?);");
ArrayList<String> pins2 = new ArrayList<String>();
Matcher m2 = pinPattern2.matcher(strManualproResponce2);
while (m2.find()) {
pins2.add(m2.group(1));
s = m2.group(1);
}
}else
{
Pattern pinPattern2 = Pattern.compile(paternField + "=(.*?);");
ArrayList<String> pins2 = new ArrayList<String>();
Matcher m2 = pinPattern2.matcher(strManualproResponce2);
while (m2.find()) {
pins2.add(m2.group(1));
s = m2.group(1);
}
}
return s;
}
Your question is a little bit cryptic, from what I am understanding is that the code is not working for when you would like to match/extract the value for the AgentId field. The issue seems to be with your regular expression: "^"+paternField + "=(.*?);" assumes that the text AgentId will be at the beginning of your string, which is not since at the beginning of your string you have IsPrimaryAgentId.
Also, your current regex will return true both for IsPrimaryAgentId and AgentId since they both contain the substring: AgentId. To fix this, you can either use this regex: \\s+AgentId=(.*?);, this will require a white space before the AgentId text.
Another option would be (if your AgentId will always be numerical) to use this: AgentId=(\\d+);.