Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a better way to determine multiple ranges of character?

Tags:

c

range

ascii

I'm currently writing code in C, which selects symbols and numbers from whole ASCII-available characters. As a beginner of programmer, I usually did

if ((i > 25 && i < 50) || (i > 100 && i < 200)) { contents } 

for the variable i being between 25~50, 100~200 (exclusive) to fit the condition.

If I want to set multiple ranges like 32~64(! to @) and 91~96([ to `) and 123~126({ to ~) then would there be any better (meaning shorter or simpler code) or should I stick with this method, keep adding each range as in the code above?

like image 536
Kagamin Avatar asked Jul 13 '16 04:07

Kagamin


People also ask

How do you check if a number is between a range?

If x is in range, then it must be greater than or equal to low, i.e., (x-low) >= 0. And must be smaller than or equal to high i.e., (high – x) <= 0. So if result of the multiplication is less than or equal to 0, then x is in range.


3 Answers

For your specific case, the <ctype.h> collection of functions would do

if (isprint(i) && !isalpha(i))

Added bonus: It even works on non-ascii systems.

like image 186
a3f Avatar answered Oct 21 '22 04:10

a3f


You can write a function that checks if the value belongs to any of given ranges:

struct Range {
        int min;
        int max;
};

bool in_ranges(int character, struct Range *ranges, size_t num_ranges) {
        for(size_t i = 0; i < num_ranges; ++i) {
                if(ranges[i].min < character && character < ranges[i].max)
                        return true;
        }
        return false;
}

int main() {
        struct Range rngs[] = {{25,50}, {100,200}};
        bool at_sign_si_in_range = in_ranges('@', rngs, 2);
        return 0;
}

It makes editing ranges much simpler and improves readability. Also, if you continue to write all ranges in conditional clause as in your example, consider checking ranges like

lower_bound < value && value < upper_bound

It looks like mathematical notation (x < a < y) and also seems easier to read.

like image 41
Sergey Avatar answered Oct 21 '22 04:10

Sergey


If you are using single byte characters, you may be able to get better performance using an array of flags, setting either individual bits or whole bytes to indicate character values that are in one of the ranges.

If you are writing code for an Intel processor that supports the SSE 4.2 instructions, you might want consider using PCMPISTRI or similar, which can compare up to 16 single byte characters against up to 8 different ranges in a single instruction.

like image 27
Simon Spero Avatar answered Oct 21 '22 04:10

Simon Spero