How can I switch case for each letter in a string

2020-05-09 22:57发布

I need to convert this into this using PostgreSQL

dxItw9a4 --> DXiTW9A4

Is there any function or way that is already set?

4条回答
干净又极端
2楼-- · 2020-05-09 23:10

It sounds like the OP is looking for a SQL version of the swapcase() function found in many client-side languages. A few thoughts:

  1. Use swapcase() on the client side. I'd do that.
  2. Figure out a clever regex? I'm not that clever.
  3. Roll something by hand.

I figured I'd give #3 a try, and wrote some code. The kindest thing I can say about this function is that it works...but I doubt it's much good. I'm trying to beef up my PL/pgSQL skills, so any comments on improving the code welcomed. It's so much easier to write a lot of things in most other languages...but there are plenty of cases where pushing the logic onto the server is beneficial, I figure it's worth putting in some effort to get comfortable in PL/pgSQL. But, again, I'd use swapcase(), or a hand-rolled equivalent, on the client side, I'd expect.

CREATE OR REPLACE FUNCTION swapcase(in_text text) RETURNS text as
$BODY$
DECLARE
    out_text text;
    test_char text;
    ascii_code smallint;
    characters_arr_text  text[];
begin

   out_text  :='';
   test_char := '';
   select into characters_arr_text regexp_split_to_array(in_text,'');

    FOREACH test_char IN array characters_arr_text LOOP

        ascii_code := ascii(test_char);

        IF (ascii_code BETWEEN 65 and 90) THEN 
            out_text := out_text || LOWER(test_char);

        ELSIF (ascii_code BETWEEN 97 and 122) THEN 
            out_text := out_text || UPPER(test_char);

         ELSE
          out_text := out_text || test_char;
        END IF;

    END LOOP;

    RETURN out_text;

END
$BODY$
LANGUAGE 'plpgsql';

Here's a call:

select swapcase('dxItw9a4'); --  DXiTW9A4

And a longer call to show that it works:

select 'dxItw9a4' as input,
        swapcase('dxItw9a4') as output,
        'DXiTW9A4' as expected_output,
        swapcase('dxItw9a4') = 'DXiTW9A4' as pass;

Better

Here's a swapcase() function that uses GMB's code.

CREATE OR REPLACE FUNCTION swapcase(in_text text) RETURNS text as
$BODY$

    select string_agg(
                case when character ~ '[a-z]' then 
                    upper(character) 
                else 
                    lower(character)
                 end, '') as result_text

    from (select * 
            from regexp_split_to_table(in_text, '') as character) as subquery

$BODY$
LANGUAGE 'sql';
查看更多
冷血范
3楼-- · 2020-05-09 23:15

You can use the following methods supported by PostreSQL:

UPPER(string_expression)

Example:

SELECT
   CONCAT (
      UPPER (first_name),
      UPPER (last_name)
   ) as full_name
FROM
   staff;

Reference: http://www.postgresqltutorial.com/postgresql-letter-case-functions/

查看更多
够拽才男人
4楼-- · 2020-05-09 23:21

If you're only dealing with the characters A-Z, you can use the translate function in postgres to convert cases.

select TRANSLATE(
    'dxItw9a4', -- original text
    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', -characters to change
    'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' -- replacement characters.
)

You can simplify it slightly be using the upper/lower functions.

select TRANSLATE(
    'dxItw9a4',  -- original text
    upper('dxItw9a4')||lower('dxItw9a4'), --characters to search for
    lower('dxItw9a4')||upper('dxItw9a4') -- replacement characters
);

查看更多
欢心
5楼-- · 2020-05-09 23:31

Here is a solution that works by splitting the string into a resultset of charaters using regexp_split_to_table(), then converts them to the opposite case and joins them again using aggregate function string_agg():

select 
    string_agg(case when c ~ '[a-z]' then upper(c) else lower(c) end, '') res
from (
    select * from regexp_split_to_table('dxItw9a4', '') as chars(c)
) x

Demo on DB Fiddle:

| res      |
| :------- |
| DXiTW9A4 |
查看更多
登录 后发表回答