7

I have a field called "Species" which is composed by two words (e.g. 'Robinia pseudoacacia') and I would like to extract the first letter of both the words in order to get two letters (e.g. 'Rp') in the label.

There other word pairs in the field "Species" so I guess it needs a rule which specifies that the extraction must be done for the first word (e.g. substr("Species", 1, 1)) as well as for the first letter after the space.

0

4 Answers 4

8

Here's a Regular Expression method, assuming you're doing this in the QGIS Field Calculator:

 regexp_substr("yourfield",'\\w{1}') || regexp_substr("yourfield",' (\\w){1}')
2
  • 3
    @BERA without a capture group (between parentheses), the entire expression is captured and returned \\w{1} -> get the 1st word 1st character and return. ` (\\w){1}` -> find a space, followed by a word character (record it) that appears exactly once and return the capture group (i.e. the 1 letter only, without the space)
    – JGH
    Commented Dec 14, 2021 at 21:46
  • Well said @JGH - capturing groups are extremely powerful, and like you see in JGH's answer, they can be referenced later with \\n. The whole thing about the Field Calc in my answer was because OP didn't specify any software in the original question :)
    – Encomium
    Commented Dec 15, 2021 at 14:26
8

You can achieve this in a single expression, that would work with any number of words

regexp_replace(field_name,'(^| )(\\w{1})[^ ]*','\\2')

First, let's note that we are using regexp_replace to remove any char but the 1st of each word. If we use regexp_substr, the search would stop at the 1st found occurence.

Let's break it down: Anything between parenthesis is a capture group, which is numbered starting at 1.

(^| ): the start of a string, or a space
(\\w{1}): followed by any word character, exactly once. --> this is the 1st letter of each word.
[^ ]*: followed by any number (*) of character that is not (^) a space
\\2: replace everything from above with the 2nd capture group, i.e. the 1st letter of each word

enter image description here

PS: word beginning detection can certainly be improved with a bit more regex kungfu..

3
  • 2
    This is well-explained but crucially doesn't actually work for the OP's example - using 'Robinia pseudoacacia' results in 'Rinia pseudoacacia'. I think this comes from .[^ ] - strips out two characters which works in your test example but not longer strings. You are missing a + at the end to capture additional non-space characters.
    – she_weeds
    Commented Dec 14, 2021 at 0:56
  • 3
    Here is a modification that works and also captures any number of words - and also strips out non-word characters which is common in botanic names with cultivars (e.g. Robinia pseudoacacia 'Frisia' --> RpF) : regexp_replace(field_name,'(^|\\W)+(\\w{1})[^\\s]+','\\2') Would need more tweaking for hybrid binomials e.g. Platanus x acerifolia.
    – she_weeds
    Commented Dec 14, 2021 at 1:01
  • 2
    @she_weeds thanks, well spotted! I have updated the expression to end with [^ ]*, which would keep 1 letter word, and is nicely enhanced with your expression that removes it
    – JGH
    Commented Dec 14, 2021 at 12:48
7

Split string into an array by whitespace, pick first/last element, pick first letter, concat together:

concat(
substr(array_first(string_to_array( "scientificname", ' ')), 1, 1),  
substr(array_last(string_to_array( "scientificname", ' ')), 1, 1)
)

enter image description here

3

Another idea is to use this expression:

array_to_string(
    array_foreach(
        string_to_array("test", ' '), regexp_substr(@element, '^[[:alpha:]]|[0-9]')
        ),
    ' ')

It employs the following functions: array_to_string(), array_foreach(), string_to_array(), and regexp_substr()

result

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.