How to count vowels - abap

How can I count the vowels in a string ?
for example:
data: str type string value 'steave'.
and I want the output be:
2 --> e.
1 --> a.

Just loop through the string / char and collect the results into a statistical internal table. Use CA (contains any) operator for checking vowels. Example code:
DATA: str TYPE string VALUE 'steave',
l_pos TYPE sy-index,
BEGIN OF ls_stat,
char TYPE c,
count TYPE sy-index,
END OF ls_stat,
lt_stat LIKE STANDARD TABLE OF ls_stat.
DO strlen( str ) TIMES.
l_pos = sy-index - 1 .
IF str+l_pos(1) CA 'AaEeIiOoUu'.
ls_stat-char = str+l_pos(1).
ls_stat-count = 1.
COLLECT ls_stat INTO lt_stat.
ENDIF.
ENDDO.
SORT lt_stat BY count DESCENDING.
LOOP AT lt_stat INTO ls_stat.
WRITE: / ls_stat-count, '->', ls_stat-char.
ENDLOOP.

I seriously thought you were making up words at random. I hope 'vogals' are characters. Vogals I've been told, are vowels. Thank #jmoerdyk. Anyway, since you got me interested I think this may work:
vowels = 'aeiouy'
length = STRLEN(vowels).
WHILE index < length.
char = vowels+index(1).
FIND ALL OCCURENCES OF char IN yourString
MATCH COUNT occurrences
WRITE: / char,'appears', / occurrences,'times'
ADD 1 TO index.
ENDWHILE.
Seems difficult working for SAP. The language seems to work well with tables/databases, not these kind of string operations.

Related

RTTI: Get length of a character column

My function module receives a table name and a column name at runtime.
I would like to get the length of the column: How many characters are allowed in the transparent table?
I used my favorite search engine and found RTTS.
But the examples in the documentation pass a variable to the RTTS method DESCRIBE_BY_DATA; in my case, I don't have a variable, I just have the type names in table_name and column_name.
How to get the length?
For retrieving the type of a given DDIC type only known at runtime, use the method DESCRIBE_BY_NAME. The RTTI length is always returned as a number of bytes.
Example to get the type of the column CARRID of table SFLIGHT (I know it's a column of 3 characters) :
cl_abap_typedescr=>describe_by_name(
EXPORTING
p_name = 'SFLIGHT-CARRID'
RECEIVING
p_descr_ref = DATA(lo_typedescr)
EXCEPTIONS
type_not_found = 1 ).
" you should handle the error if SY-SUBRC <> 0
" Because it's SFLIGHT-CARRID, I expect 6 BYTES
ASSERT lo_typedescr->length = 6. " 3 characters * 2 bytes (Unicode)
" Length in CHARACTERS
CASE lo_typedescr->type_kind.
WHEN lo_typedescr->typekind_char
OR lo_typedescr->typekind_num
OR lo_typedescr->typekind_date
OR lo_typedescr->typekind_time
OR lo_typedescr->typekind_string.
DATA(no_of_characters) = lo_typedescr->length / cl_abap_char_utilities=>charsize.
ASSERT no_of_characters = 3.
ENDCASE.
You don't need RTTS for this. You can Do one of this
Select table DD03L with TABNAME and FIELDNAME
Use Function DDIF_FIELDINFO_GET

How to filter based on string in hive

So, I have a table of following schema
user_id int,
movie_id int,
score float,
demography string
the demography is a comma delimited string
like 'm,22,ca,.....'. This can have variable number of elements in it.
Now, I want to filter the records based on certain characterstics...
which is if demography is "m" or is from "ca" etc etc..
So, currently what I am doing is..
split the string into array (split(table.demography, "\\,")) and then explode it and do the filter.. using a where clause..
Where exploded_demography = 'm' or exploded_demography='ca' (etc etc)
But, explode causes the records to.. well.. explode.. I am trying to avoid that as it seems to bloat up the number of records..
Is there a way I can do this without exploding the records?
Try using:
find_in_set('ca', table.demography) > 0
From: https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF#LanguageManualUDF-StringFunctions
int find_in_set(string str, string strList) Returns the first
occurance of str in strList where strList is a comma-delimited string.
Returns null if either argument is null. Returns 0 if the first
argument contains any commas. For example, find_in_set('ab',
'abc,b,ab,c,def') returns 3.

Replace a part of a string using a math factor

I am using PowerShell and MS Access.
I would like to apply a math factor to what is inside the pipes in this column value.
Ex. -100.0 must become -400.0 and 100.0 must become 400.0, given the factor is 4.
I only need to modify "Min_Value" and "Max_Value" tokens (hard coded).
FiledValue comes from the database (there are multiple rows).
FieldValue isn't always exactly the same as this example, BUT the token pattern is always the same Ex. Min_Value=|.....|
function Test
{
$Factor = 4
# Hard-coded SQL query result
$FieldValue = "Min_Value=|-100.0|;Max_Value=|100.0|;COMM_ID1=|1|;"
# Compare this value with a regular expression (Issue A: This doesn't work because of the minus sign and decimal)
if ($FieldValue -match "Min_Value=\|([0-9]+)\|;Max_Value=\|([0-9]+)\|;")
{
# Trying to retreive -100.0 here...(Issue B: this doesn't work). I beleive I can only specify ||, not Min_Value=||
$TokenMinValue = $FieldValue.Split('Min_Value=||')[1]
$TokenMaxValue = $FieldValue.Split('Max_Value=||')[1]
# Trying to take the token (-100.0), multiply it by 4 and write it back where I found it (Issue C: this obvioulsy doesn't work)
$Result = $FieldValue -replace "$regex",($TokenMinValue * $Factor)
$Result = $FieldValue -replace "$regex",($TokenMaxValue * $Factor)
#The goal is for $Result to equal "Min_Value=|-400.0|;Max_Value=|400.0|;COMM_ID1=|1|;"
}
}
You didn't specify your DBMS so here's a solution using Postgres. At least you can follow the logic behind it:
select
concat(
replace(
concat('Min_Value=|', string_agg(intval,';')), ';', '|;Max_Value=|'),
'|;')
from (
select (unnest(regexp_matches('Min_Value=|10|;Max_Value=|100|;', 'Min_Value=\|([0-9]+)\|;Max_Value=\|([0-9]+)\|;'))::int*4)::TEXT as intval
) foo;
The magic happens like that:
with regexp_matches extract two integers from input string
use unnest to unpack the array into two separate rows
cast those integer values (which are text at the moment) to Integer and multiply by factor 4
use string_agg with ; as delimiter to make one string row containing both integers delimited with ;
use concat to append Min_Value=| at the beginning, so the string is now Min_Value=|40;400
use replace and replace ; with next part - |;Max_Value=| so the string is now Min_Value=|40|;Max_Value=|400
use concat again to append |; to the end of the string
Input:
Min_Value=|10|;Max_Value=|100|;
Result:
Min_Value=|40|;Max_Value=|400|;

How do I perform a LIKE query on a PostgreSQL primary id column?

If I have a number (such as 88) and I want to perform a LIKE query in Rails on a primary ID column to return all records that contain that number at the end of the ID (IE: 88, 288, etc.), how would I do that? Here's the code to generate the result, which works fine in SQLLite:
#item = Item.where("id like ?", "88").all
In PostgreSQL, I'm running into this error:
PG::Error: ERROR: operator does not exist: integer ~~ unknown
How do I do this? I've tried converting the number to a string, but that doesn't seem to work either.
Based on Erwin's Answer:
This is a very old question, but in case someone needs it, there is one very simple answer, using ::text cast:
Item.where("(id::text LIKE ?)", "%#{numeric_variable}").all
This way, you find the number anywhere in the string.
Use % wildcard to the left only if you want the number to be at the end of the string.
Use % wildcard to the right also, if you want the number to be anywhere in the string.
Simple case
LIKE is for string/text types. Since your primary key is an integer, you should use a mathematical operation instead.
Use modulo to get the remainder of the id value, when divided by 100.
Item.where("id % 100 = 88")
This will return Item records whose id column ends with 88
1288
1488
1238872388
862388
etc...
Match against arbitrary set of final two digits
If you are going to do this dynamically (e.g. match against an arbitrary set of two digits, but you know it will always be two digits), you could do something like:
Item.where(["id % 100 = ?", last_two_digits)
Match against any set or number of final digits
If you wanted to match an arbitrary number of digits, so long as they were always the final digits (as opposed to digits appearing elsewhere in the id field), you could add a custom method on your model. Something like:
class Item < ActiveRecord
...
def find_by_final_digits(num_digits, digit_pattern)
# Where 'num_digits' is the number of final digits to match
# and `digit_pattern` is the set of final digits you're looking fo
Item.where(["id % ? = ?", 10**num_digits, digit_pattern])
end
...
end
Using this method, you could find id values ending in 88, with:
Item.find_by_final_digits(2, 88)
Match against a range of final digits, of any length
Let's say you wanted to find all id values that end with digits between 09 and 12, for whatever reason. Maybe they represent some special range of codes you're looking up. To do this you could do another custom method to use Postgres' BETWEEN to find on a range.
def find_by_final_digit_range(num_digits, start_of_range, end_of_range)
Item.where(["id % ? BETWEEN ? AND ?", 10**num_digits, start_of_range, end_of_range)
end
...and could be called using:
Item.find_by_final_digit_range(2, 9, 12)
...of course, this is all just a little crazy, and probably overkill.
The LIKE operator is for string types only.
Use the modulo operator % for what you are trying to do:
#item = Item.where("(id % 100) = ?", "88").all
I doubt it "works" in SQLite, even though it coerces the numeric types to strings. Without leading % the pattern just won't work.
-> sqlfiddle demo
Cast to text and use LIKE as you intended for arbitrary length:
#item = Item.where("(id::text LIKE ('%'::text || ?)", "'12345'").all
Or, mathematically:
#item = Item.where("(id % 10^(length(?)) = ?", "'12345'", "12345").all
LIKE operator does not work with number types and id is the number type so you can use it with concat
SELECT * FROM TABLE_NAME WHERE concat("id") LIKE '%ID%'

SQL query TO_INTEGER substr

Please explain me how to understand the next query
TO_INTEGER(substr(NAME,1,length(NAME)-3))*100
You are taking a substring of NAME ,which happens to be integer in string form and converting it to integer and multiplying it with 100.
For example, NAME is '1234CDE'
The innermost section takes a substring from the input value NAME, starting from position 1 and with a length of equal to the length of the original string minus 3:
substr(NAME,1,length(NAME)-3) -- >> '1234'
The outer function converts the extracted substring to integer:
TO_INTEGER('1234') -- >> 1234 (as integer)
Lastly there's a simple multiplication:
1234 * 100 -- >> 123400
so
TO_INTEGER(substr('1234CDE',1,length('1234CDE')-3)) * 100 -- >> 123400