When trying to store in an Oracle SQL table a string of more than 100 chars, while the field limitation is 1000 bytes which I understood is ~1000 English chars, I'm getting out of bounds exception:
StringIndexOutOfBoundsException: String index out of range: -3
What might be the cause for this low limitation?
Thanks!
EDIT :
The code where the error occurs is (see chat):
// Commenting the existing code, because for sensitive information
// toString returns masked data
int nullSize = 5;
int i = 0;
// removing '[' and ']', signs and fields with 'null' value and also add
// ';' as delimiter.
while (i != -1) {
int index1 = str.indexOf('[', i);
int index2 = str.indexOf(']', i + 1);
i = index2;
if (index2 != -1 && index1 != -1) {
int index3 = str.indexOf('=', index1);
if (index3 + nullSize > str.length() || !str.substring(index3 + 1, index3 + nullSize).equals("null")) {
String str1 = str.substring(index1 + 1, index2);
concatStrings = concatStrings.append(str1);
concatStrings = concatStrings.append(";");
}
}
}
Generally, when the string to store in a varchar field is too long, it is cropped silently. Anyway when there is an error message, it is generally specific. The error seems to be related to a operation on a string (String.substring()?).
Furthermore, even when the string is encoded in UTF-8, the ratio characters/bytes shouldn't be that low.
You really should put the code sample where your error occurs in you question and the string causing this and also have a closer look at the stacktrace to see where the error occurs.
From the code you posted in your chat, I can see this line of code :
String str1 = str.substring(index1 + 1, index2);
You check that index1 and index2 are different than -1 but you don't check if (index1 + 1) >= index2 which makes your code crash.
Try this with str = "*]ab=null[" (which length is under 100 characters) but you can also get the error with a longer string such as "osh]] [ = null ]Clipers: RRR was removed by user and customer called in to have it since it was an RRT".
Once again the size of the string doesn't matter, only the content!!!
You can reproduce your problem is a closing square bracket (]) before an opening one([) and between them an equal sign (=) followed (directly or not) by the "null" string.
I agree with Jonathon Ogden "limitations of 1000 bytes does not necessarily mean 1000 characters as it depends on character encoding".
I recommend you to Alter column in your Oracle table from VARCHAR2(1000 Byte) to VARCHAR2(1000 Char).
Related
I am trying to write a code that will loop you in case you provide wrong data. The problem is that I need to have some type of "Bad data" message for both 2 cases:
- you enter not an integer value
- you enter the value below 0
In this code if you type a letter, it loops you with a message: "Bad data", but if you type for example negative value like -10 Bad data is not appearing (even though validation works and you need to correct number to positive)
How can I do it more universal, so in both scenarios sysout with print on-screen Bad data
Random rand = new Random();
int los = rand.nextInt(11);
int NumberOfPlayers ;
Scanner scan7 = new Scanner(System.in);
System.out.println(" Type number of players :");
do {
while (!scan7.hasNextInt()){
System.out.println(" Bad data");
scan7.next();
}
NumberOfPlayers = scan7.nextInt();
}while (NumberOfPlayers < 0);
you are only validating if scanner has next int, you do not validate it's value, and integers can be negative.
try this solution:
do {
while (!scan7.hasNextInt()) {
System.out.println(" Bad data");
scan7.next();
}
NumberOfPlayers = scan7.nextInt();
if (NumberOfPlayers <= 0) {
System.out.println(" Number must be larger than zero");
}
} while (NumberOfPlayers <= 0);
After checking for next int, I added part checking value of provided int.
ALSO please remember about naming variables and classes - start with small letter, so in your case NumberOfPlayers should be numberOfPlayers.
Why you named scanner scan7? is there valid reason for that name? if no, you should avoid adding numbers to names.
I have the following code:
#include <stdio.h>
int main(void) {
char list[3][7] = { "One", "Two", "Three"} ;
char item[7]; // originally I had posted "char item[3];" by mistake
int i;
for( i=0; i<2; i++ ) {
sprintf(item, "%-7s", list[i]);
printf( "%d %s", i, item );
}
printf("\n\r");
for( i=0; i<2; i++ ) {
sprintf(item, "%-7s", list[i]);
printf( "%d %s", i, item );
}
printf("\n\r");
return 0;
}
I expect the following output
0 One 1 Two
0 One 1 Two
However, instead I get:
0 One 1 Two
0 1 Two
Note the missing text "One" the second time it prints.
Can someone explain what's happening here?
Thanks!
With item declared as:
char item[7];
the code exposes undefined behaviour because sprintf(item, "%-7s") attempts to write at least 8 characters into item.
The documentation of sprintf() explains (the emphasis is mine):
Writes the results to a character string buffer. The behavior is undefined if the string to be written (plus the terminating null character) exceeds the size of the array pointed to by buffer.
-7 in the format string "%-7s" is interpreted as:
(optional) integer value or * that specifies minimum field width. The result is padded with space characters (by default), if required, on the left when right-justified, or on the right if left-justified. In the case when * is used, the width is specified by an additional argument of type int. If the value of the argument is negative, it results with the - flag specified and positive field width. (Note: This is the minimum width: The value is never truncated.)
In order to avoid the undefined behaviour, the size of item must be at least 8 but keep in mind that if the string to format is longer than 7 characters it is not truncated, the result becomes longer than 8 characters and it overflows item again.
Why you get the output you get?
The calls to sprintf(item, "%-7s", list[i]); in the first loop write 8 characters in a buffer of 7 characters. The extra character (which is \0) incidentally happens to overwrite the first character of list[0] changing it into an empty string. This is just one random behaviour, compiling the code with a different compiler or different compiling options could produce a different behaviour.
When you do the sprintf(item, "%-7s", list[i]); you are, essentially, copying the string from list[i] into your char array item.
So list[2] -> "three" is 5 chars plus the nul terminator, but item is only 3 chars long -- you are overflowing item and writing over some other memory, which could very well be part of list.
Change item to be char item[7] so it matches the length of 7 declared in your 2nd dimension in list[3][7]. When I did that I got your expected output.
(I used https://repl.it/languages/C to test)
I got a question in vb.net
can I identify each of the character in string
for an example
i got a string of "Hello!. Good Afternoon!"
from this string can i trim away the period symbol?
Thank you
You should look at the methods of the String class, as they support different forms of string manipulation.
At its simplest, the Replace() method can be used to replace all occurrences of a period character with an empty string.
Alternatively, you can use the IndexOf() method to locate a specific string (e.g. the period) and the Remove() method to remove that character.
According to my 8-ball Magic, you actually want to :
Remove concecutive punctuation from a string:
With a Regex we are going to find all punctuation in the string.
The index of Match will be into an int[].
We will go iterate throught the array to find if the index is concecutive to the last punctuation index.
We will delete all the punctuation starting by the last one. Because starting with the 1rst will modify the index.
Code:
string Input = "....Thalassius! vero ea--*/-*/-- tempestate+- fectus";
string Output = Input;
var regex = new Regex(#"[^\w\s]|_"); // *1.
var matches = regex.Matches(Input) ;
var MatchesIndex = matches .Cast<Match>()
.Select(match => match.Index)
.ToArray(); // *2.
int last = 0;
List<int> toDelete = new List<int>();
for (int i = 0; i < MatchesIndex.Length; i++) // *3.
{
if ( MatchesIndex[i] == last + 1)
toDelete.Add(MatchesIndex[i]);
last = MatchesIndex[i];
}
foreach (int i in toDelete.OrderByDescending(x => x)) // *4.
Output = Output.Remove(i, 1);
Console.WriteLine("Input : " + Input);
Console.WriteLine("Output : " + Output);
C# Snippet
You can learn more about the regex used, thanks to #John Kugelman.
Writing a basic program to count the number of words in a string. I've changed my original code to account for multiple spaces between words. By setting one variable to the current index and one variable to the previous index and comparing them, I can say "if this current index is a space, but the previous index contains something other than a space (basically saying a character), then increase the word count".
int main(int argc, const char * argv[]) {
#autoreleasepool {
//establishing the string that we'll be parsing through.
NSString * paragraph = #"This is a test paragraph and we will be testing out a string counter.";
//we're setting our counter that tracks the # of words to 0
int wordCount = 0;
/*by setting current to a blank space ABOVE the for loop, when the if statement first runs, it's comparing [paragraph characterAtIndex:i to a blank space. Once the loop runs through for the first time, the next value that current will have is characterAtIndex:0, while the if statement in the FOR loop will hold a value of characterAtIndex:1*/
char current = ' ';
for (int i=0; i< paragraph.length; i++) {
if ([paragraph characterAtIndex:i] == ' ' && (current != ' ')) {
wordCount++;
}
current = [paragraph characterAtIndex:i];
//after one iteration, current will be T and it will be comparing it to paragraph[1] which is h.
}
wordCount ++;
NSLog(#"%i", wordCount);
}
return 0;
}
I tried adding "or" statements to account for delimiters such as ";" "," and "." instead of just looking at a space. It didn't work...any idea what I can do, logically speaking, to account for anything that isn't a letter (but preferably just limiting it to these four delimiters - . , ; and space.
A standard way to solve these types of problems is to build a finite state machine, your code isn't quite one but its close.
Instead of thinking about comparing the previous and current characters think in terms of states - you can start with just two, in a word and not in a word.
Now for each state you consider what the current character implies in terms of actions and changes to the state. For example, if the state is not in a word and the current character is a letter then the action is increment word count and the next state is in a word.
In (Objective-)C you can build a simple finite state machine using an enum to give the states names and a case statement inside a loop. In pseudo-code this is something like:
typedef enum { NotInWord, InWord } State;
State currentState = NotInWord;
NSUInteger wordCount = 0;
for currentChar in sourceString
case currentState of
NotInWord:
if currentChar is word start character -- e.g. a letter
then
increment wordCount;
currentState = InWord;
InWord:
if currentChar is not a word character -- e.g. a letter
then
currentState = NotInWord;
end case
end for
The above is just a step from your original algorithm - recasting it in terms of states rather than the previous character.
Now if you want to get smarter you can add more states. For example how many words are there in "Karan's question"? Two. So you might want to allow a single apostrophe in a word. To handle that you can add a state AfterApostrophe whose logic is the same as the current InWord; and modify InWord logic to include if the current character is an apostrophe the next state is AfterApostrophe - that would allow one apostrophe in a word (or its end, which is also valid). Next you might want to consider hyphenated words, etc...
To test if a character is a particular type you have two easy choices:
If this is just an exercise and you are happy to stick with the ASCII range of characters there are functions such as isdigit(), isletter() etc.
If you want to handle full Unicode you can use the NSCharacterSet type with its pre-defined sets for letters, digits, etc.
See the documentation for both of the above choices.
HTH
I don't understand, You should be able to add or statements....
int main(void) {
char paragraph[] = "This is a test paragraph,EXTRAWORDHERE and we will be testing out a string.";
char current = ' ';
int i;
int wordCount = 0;
for (i = 0; i < sizeof(paragraph); i++){
if ((paragraph[i] == 32 || paragraph[i] == 44) && !(current == 32 || current == 44)){ //32 = ascii for space, 44 for comma
wordCount++;
}
current = paragraph[i];
}
wordCount++;
printf("%d\n",wordCount);
return 0;
}
I suppose it would be better to change the comparison of current from a not equal to into an equal to. Hopefully that helps.
I currently have code in objective C that can pull out an integer's most significant digit value. My only question is if there is a better way to do it than with how I have provided below. It gets the job done, but it just feels like a cheap hack.
What the code does is that it takes a number passed in and loops through until that number has been successfully divided to a certain value. The reason I am doing this is for an educational app that splits a number up by it's value and shows the values added all together to produce the final output (1234 = 1000 + 200 + 30 + 4).
int test = 1;
int result = 0;
int value = 0;
do {
value = input / test;
result = test;
test = [[NSString stringWithFormat:#"%d0",test] intValue];
} while (value >= 10);
Any advice is always greatly appreciated.
Will this do the trick?
int sigDigit(int input)
{
int digits = (int) log10(input);
return input / pow(10, digits);
}
Basically it does the following:
Finds out the number of digits in input (log10(input)) and storing it in 'digits'.
divides input by 10 ^ digits.
You should now have the most significant number in digits.
EDIT: in case you need a function that get the integer value at a specific index, check this function out:
int digitAtIndex(int input, int index)
{
int trimmedLower = input / (pow(10, index)); // trim the lower half of the input
int trimmedUpper = trimmedLower % 10; // trim the upper half of the input
return trimmedUpper;
}