{"id":25456811,"url":"https://github.com/szaghi/stringifor","last_synced_at":"2026-02-28T12:47:32.448Z","repository":{"id":43699520,"uuid":"58048517","full_name":"szaghi/StringiFor","owner":"szaghi","description":"Strings Fortran Manipulator with steroids","archived":false,"fork":false,"pushed_at":"2023-06-30T06:44:04.000Z","size":17389,"stargazers_count":85,"open_issues_count":4,"forks_count":21,"subscribers_count":11,"default_branch":"master","last_synced_at":"2024-06-12T18:55:16.891Z","etag":null,"topics":["fortran","oop","parsing","string","string-manipulation","strings"],"latest_commit_sha":null,"homepage":"","language":"Fortran","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/szaghi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.bsd-2.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-05-04T11:59:22.000Z","updated_at":"2024-05-31T15:11:43.000Z","dependencies_parsed_at":"2022-07-20T18:49:20.990Z","dependency_job_id":null,"html_url":"https://github.com/szaghi/StringiFor","commit_stats":null,"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/szaghi%2FStringiFor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/szaghi%2FStringiFor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/szaghi%2FStringiFor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/szaghi%2FStringiFor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/szaghi","download_url":"https://codeload.github.com/szaghi/StringiFor/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239394685,"owners_count":19631122,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fortran","oop","parsing","string","string-manipulation","strings"],"created_at":"2025-02-18T01:51:21.799Z","updated_at":"2025-11-02T10:30:32.483Z","avatar_url":"https://github.com/szaghi.png","language":"Fortran","readme":"\u003ca name=\"top\"\u003e\u003c/a\u003e\n\n# StringiFor [![GitHub tag](https://img.shields.io/github/tag/szaghi/StringiFor.svg)](https://github.com/szaghi/StringiFor/releases)\n\n[![License](https://img.shields.io/badge/license-GNU%20GeneraL%20Public%20License%20v3%20,%20GPLv3-blue.svg)]()\n[![License](https://img.shields.io/badge/license-BSD2-red.svg)]()\n[![License](https://img.shields.io/badge/license-BSD3-red.svg)]()\n[![License](https://img.shields.io/badge/license-MIT-red.svg)]()\n\n[![Status](https://img.shields.io/badge/status-stable-brightgreen.svg)]()\n[![CI Status](https://github.com/szaghi/StringiFor/actions/workflows/ci.yml/badge.svg)](https://github.com/szaghi/StringiFor/actions)\n[![Coverage Status](https://img.shields.io/codecov/c/github/szaghi/StringiFor.svg)](https://app.codecov.io/gh/szaghi/StringiFor)\n\n### StringiFor, Strings Fortran Manipulator, yet another strings Fortran module\nA KISS pure Fortran library providing  astrings (class) manipulator for modern (2003+) Fortran projects.\n\n+ StringiFor is a pure Fortran (KISS) library providing a strings manipulator for modern Fortran projects;\n+ StringiFor is Fortran 2003+ standard compliant;\n- StringiFor is OOP designed;\n- StringiFor is TDD designed;\n+ StringiFor is a Free, Open Source Project.\n\n#### Issues\n\n[![GitHub issues](https://img.shields.io/github/issues/szaghi/StringiFor.svg)]()\n\n#### Compiler Support\n\n[![Compiler](https://img.shields.io/badge/GNU-v9.2.0+-brightgreen.svg)]()\n[![Compiler](https://img.shields.io/badge/Intel-v19.0.4+-brightgreen.svg)]()\n[![Compiler](https://img.shields.io/badge/IBM%20XL-not%20tested-yellow.svg)]()\n[![Compiler](https://img.shields.io/badge/g95-not%20tested-yellow.svg)]()\n[![Compiler](https://img.shields.io/badge/NAG-not%20tested-yellow.svg)]()\n[![Compiler](https://img.shields.io/badge/PGI-not%20tested-yellow.svg)]()\n\n---\n\n[What is StringiFor?](#what-is-stringifor?) | [Main features](#main-features) | [Copyrights](#copyrights) | [Download](#download) | [Compilation](#compilation) | [Documentation](#documentation) | [Comparison to other Approaches](#comparison-to-other-approaches)\n\n---\n\n## What is StringiFor?\n\nModern Fortran standards (2003+) have introduced a better support for characters variables, but Fortraners still do not have the power on dealing with strings of other more-rich-programmers, e.g. Pythoners. Allocatable deferred length character variables are now quantum-leap with respect the old inflexible Fortran characters, but it is still not enough for many Fortraners. Moreover, Fortran does not provide builtin methods for widely used strings manipulations offered by other languages, e.g. UPPER/lowercase transformation, tokenization, etc... StringiFor attempts to fill this lack.\n\nGo to [Top](#top)\n\n## Main features\n\nStringiFor exposes only one class (OO-designed), the `string` type, that should be used as a more powerful string variable with respect a standard Fortran `character` variable. The main features of this class are:\n\n* [x] seamless interchangeability with standard character variables, e.g. concatenation, IO, etc...;\n* [x] handy builtin methods, e.g. split, search, basename, join, etc...;\n* [x] low memory consumption: only one deferred length allocatable character member is stored, allowing for efficient memory allocation in array of strings, the elements of which can have different lengths;\n+ [x] safe: almost all methods are elemental or pure;\n+ [x] robust: the library is Test Driven Developed [TDD](https://en.wikipedia.org/wiki/Test-driven_development), a comprehensive tests suite is provided.\n\nAny feature request is welcome.\n\nGo to [Top](#top)\n\n---\n\n### A Taste of StringiFor\n\nStringiFor is very handy...\n\n+ [Basic IO](#basic_io)\n+ [String manipulation](#string_manipulation)\n+ [Numbers handling](#numbers_handling)\n+ [Complex scenario](#complex_scenario)\n\n#### Basic IO\n\nThe class `string`  IO is overloaded by defined write/read TBP. Moreover, dedicated methods and operators can be exploited for IO, e.g.\n\n```fortran\nuse stringifor\ntype(string) :: astring\n\nastring = 'Hello World'\nprint \"(A)\", astring%chars() ! \"chars\" method returns a standard character variable\nprint \"(DT)\", astring        ! defined IO (in gfortran is available for GNU GCC \u003e= 7.1)\nprint \"(A)\", astring//''     ! on-the-fly conversion to standard character by means of concatenation\n```\n\n#### String manipulation\n\nThe class `string` has many methods for a plethora of strings manipulations, e.g.\n\n```fortran\nuse stringifor\ntype(string) :: astring\ntype(string) :: strings(3)\n\nastring = '0123456789'\nprint \"(A)\", astring%reverse()//'' ! print \"9876543210\"\n\nastring = 'Hello World'\nprint \"(A)\", astring%replace(old='World', new='People')//'' ! print \"Hello People\"\n\nastring = 'Hello World'\nstrings = astring%partition(sep='lo Wo')\nprint \"(A)\", 'Before sep: \"'//strings(1)//'\"' ! print \"Hel\"\nprint \"(A)\", 'Sep itself: \"'//strings(2)//'\"' ! print \"lo Wo\"\nprint \"(A)\", 'After sep:  \"'//strings(3)//'\"' ! print \"rld\"\n\nstrings(1) = 'one'\nstrings(2) = 'two'\nstrings(3) = 'three'\nprint \"(A)\", astring%join(strings)//''          ! print \"oneHello WorldtwoHello Worldthree\"\nprint \"(A)\", astring%join(strings, sep='-')//'' ! print \"one-two-three\"\n\nastring = ' a StraNgE caSe var'\nprint \"(A)\", astring%camelcase()//'' ! print \" AStrangeCaseVar\"\nprint \"(A)\", astring%snakecase()//'' ! print \" a_strange_case_var\"\nprint \"(A)\", astring%startcase()//'' ! print \" A Strange Case Var\"\n```\n\n#### Numbers handling\n\nStringiFor, by means of the [portability environment library, PENF](https://github.com/szaghi/PENF) can handle numbers (reals and integers) effortless. The string/number *casting* (to/from and viceversa) is done by overloaded assignments (for all kinds of integers and reals). For convenience, StringiFor exposes the PENF number *portable* kind parameters.\n\n```fortran\nuse stringifor\ntype(string) :: astring\n\nastring = 127 _I1P       ! \"I1P\" is the PENF kind for 1-byte-like integer.\nprint \"(A)\", astring//'' ! print \"+127\"\n\nastring = 3.021e6_R4P    ! \"R4P\" is the PENF kind for 4-byte-like real.\nprint \"(A)\", astring//'' ! print \"+0.302100E+07\"\n\nastring = \"3.4e9\" ! assign to a string without the necessity to define a real kind\nif (astring%is_number()) then\n  if (astring%is_real()) then\n    print \"(E13.6)\", astring%to_number(kind=1._R4P) ! print \" 0.340000E+10\" using a 4-byte-like kind\n  endif\nendif\n```\n\n#### Complex scenario\n\nStingiFor is developed to improve the poor Fortran people with *daily* strings-usage, however, also complex scenario is taken into account, e.g. file parsing, OS operations, etc...\n\n```fortran\nuse stringifor\ntype(string) :: astring\n\n! OS like manipulation\nastring = '/bar/foo.tar.bz2'\nprint \"(A)\", astring%basedir()//''                       ! print \"/bar\"\nprint \"(A)\", astring%basename()//''                      ! print \"foo.tar.bz2\"\nprint \"(A)\", astring%basename(extension='.tar')//''      ! print \"foo\"\nprint \"(A)\", astring%basename(strip_last_extension=.true.)//'' ! print \"foo.tar\"\n\n! XML like tag parsing\nastring = '\u003ctest\u003e \u003cfirst\u003e hello \u003c/first\u003e \u003cfirst\u003e not the first \u003c/first\u003e \u003c/test\u003e'\nprint \"(A)\", astring%search(tag_start='\u003cfirst\u003e', tag_end='\u003c/first\u003e')//'' ! print \"\u003cfirst\u003e hello \u003c/first\u003e\"\n```\n\n##### A naive CSV parser\n\nThis is just a provocation, but with StringiFor it is easy to develop a naive CSV parser. Let us assume we want to parse a cars-price database as the following one\n\n```csv\nYear, Make, Model, Description, Price\n1997, Ford, E350   , ac abs moon, 3000.00\n1999, Chevy, Venture \"Extended Edition\"  , , 4900.00\n1999, Chevy, Venture \"Extended Edition Very Large\", , 5000.00\n```\n\nWell, parsing it and handling its cells values is very easy by means of StringiFor\n\n```fortran\nuse stringifor\n\nimplicit none\ntype(string)              :: csv            !\u003c The CSV file as a single stream.\ntype(string), allocatable :: rows(:)        !\u003c The CSV table rows.\ntype(string), allocatable :: columns(:)     !\u003c The CSV table columns.\ntype(string), allocatable :: cells(:,:)     !\u003c The CSV table cells.\ntype(string)              :: most_expensive !\u003c The most expensive car.\nreal(R8P)                 :: highest_cost   !\u003c The highest cost.\ninteger                   :: rows_number    !\u003c The CSV file rows number.\ninteger                   :: columns_number !\u003c The CSV file columns number.\ninteger                   :: r              !\u003c Counter.\n\n! parsing the just created CSV file: all done 9 statements!\ncall csv%read_file(file='cars.csv')              ! read the CSV file as a single stream\ncall csv%split(tokens=rows, sep=new_line('a'))   ! get the CSV file rows\nrows_number = size(rows, dim=1)                  ! get the CSV file rows number\ncolumns_number = rows(1)%count(',') + 1          ! get the CSV file columns number\nallocate(cells(1:columns_number, 1:rows_number)) ! allocate the CSV file cells\ndo r=1, rows_number                              ! parse all cells\n  call rows(r)%split(tokens=columns, sep=',')    ! get current columns\n  cells(1:columns_number, r) = columns           ! save current columns into cells\nenddo\n\n! now you can do whatever with your parsed data\n! print the table in markdown syntax\nprint \"(A)\", 'A markdown-formatted table'\nprint \"(A)\", ''\nprint \"(A)\", '|'//csv%join(array=cells(:, 1), sep='|')//'|'\nprint \"(A)\", '|'//repeat('----|', size(columns)) ! printing separators\ndo r=2, rows_number\n  print \"(A)\", '|'//csv%join(array=cells(:, r), sep='|')//'|'\nenddo\nprint \"(A)\", ''\n! find the most expensive car\nprint \"(A)\", 'Searching for the most expensive car'\nmost_expensive = 'unknown'\nhighest_cost = -1._R8P\ndo r=2, rows_number\n  if (cells(5, r)%to_number(kind=1._R8P)\u003e=highest_cost) then\n    highest_cost = cells(5, r)%to_number(kind=1._R8P)\n    most_expensive = csv%join(array=[cells(2, r), cells(3, r)], sep=' ')\n  endif\nenddo\nprint \"(A)\", 'The most expensive car is : '//most_expensive\n```\n\nSee the test program [csv_naive_parser](https://github.com/szaghi/StringiFor/blob/master/src/tests/csv_naive_parser.f90) for a working example.\n\nObviously, this is a naive parser without any robustness, but it proves the usefulness of the StringiFor approach.\n\nGo to [Top](#top)\n\n## Copyrights\n\nStringiFor is an open source project, it is distributed under a multi-licensing system:\n\n+ for FOSS projects:\n  - [GPL v3](http://www.gnu.org/licenses/gpl-3.0.html);\n+ for closed source/commercial projects:\n  - [BSD 2-Clause](http://opensource.org/licenses/BSD-2-Clause);\n  - [BSD 3-Clause](http://opensource.org/licenses/BSD-3-Clause);\n  - [MIT](http://opensource.org/licenses/MIT).\n\nAnyone is interest to use, to develop or to contribute to StringiFor is welcome, feel free to select the license that best matches your soul!\n\nMore details can be found on [wiki](https://github.com/szaghi/StringiFor/wiki/Copyrights).\n\nGo to [Top](#top)\n\n## Download\n\nStringiFor home is at [https://github.com/szaghi/StringiFor](https://github.com/szaghi/StringiFor). It uses `git submodule` to handle the third party dependencies. To download all the source files you can:\n\n+ clone this repository (all dependencies are satisfied):\n  + `git clone https://github.com/szaghi/StringiFor`\n  + `cd StringiFor`\n  + `git submodule update --init`\n+ download only the StringiFor sources, all other dependencies must be downloaded manually:\n  + download the latest master-branch archive:\n    + `wget https://github.com/szaghi/StringiFor/archive/master.zip`\n    + `unzip StringiFor-master.zip`\n    + `cd StringiFor-master`\n    + `git submodule update --init`\n  + download a release archive at [https://github.com/szaghi/StringiFor/releases](https://github.com/szaghi/StringiFor/releases)\n\n#### Third Party dependencies\n\nCurrently StringiFor depends on:\n\n+ [FACE](https://github.com/szaghi/FACE)\n+ [PENF](https://github.com/szaghi/PENF)\n+ [BeFoR64](https://github.com/szaghi/BeFoR64)\n\n\u003e The third party libraries are necessary for building StringiFor. StringiFor is constantly made up-to-date with third party libraries master branch or their latest release.\n\nIf you download a release of StringiFor manually (without git) you must download manually the above dependencies and place them into `src/third_party` sub-directory of the project root-tree.\n\nGo to [Top](#top)\n\n## Compilation\n\nStringiFor is a modern Fortran project thus a modern Fortran compiler is need to compile the project. In the following table the support for some widely-used Fortran compilers is summarized.\n\n| Compiler Vendor Support                                                    | Notes        |\n|----------------------------------------------------------------------------|--------------|\n|[![Compiler](https://img.shields.io/badge/GNU-v9.2.0+-brightgreen.svg)]()   | full support |\n|[![Compiler](https://img.shields.io/badge/Intel-v19.0.4+-brightgreen.svg)]()| full support |\n|[![Compiler](https://img.shields.io/badge/IBM%20XL-vx.y-yellow.svg)]()      | not tested   |\n|[![Compiler](https://img.shields.io/badge/g95-vx.y-yellow.svg)]()           | not tested   |\n|[![Compiler](https://img.shields.io/badge/NAG-vx.y-yellow.svg)]()           | not tested   |\n|[![Compiler](https://img.shields.io/badge/PGI-vx.y-yellow.svg)]()           | not tested   |\n\nThe library is modular, namely it exploits Fortran modules. As a consequence, there is compilation-cascade hierarchy to build the library. To correctly build the library the following approaches are supported\n\n+ [Build by means of FoBiS](#build-by-means-of-fobis): full support;\n+ [Build by means of GNU Make](#build-by-means-of-gnu-make): support for GNU Make is not provided, a Makefile is provided, but it is likely outdated and could not work as expected. Help for maintaining GNU Make support is strongly welcome, feel free to join this progect.\n+ [Build by means of CMake](#build-by-means-of-fobis): support for CMake is not provide, some CMake support is provided by great users, but it could be outdated. Help for maintaining CMake support is strongly welcome, feel free to join this progect.\n\nThe FoBiS building support is the most complete and the only one officially supported by the author, as it is the one used for the developing StringiFor.\n\n### Build by means of FoBiS\n\nA `fobos` file is provided to build the library by means of the Fortran Building System [FoBiS](https://github.com/szaghi/FoBiS).\n\n#### Build all tests\n\nType\n\n```shell\nFoBiS.py build\n```\n\nAfter (a successuful) building a directory `./exe` is created containing all the compiled tests that constitute the StringiFor *regression-tests-suite*, e.g.\n\n```bash\n→ FoBiS.py build\nBuilder options\nDirectories\n  Building directory: \"exe\"\n  Compiled-objects .o   directory: \"exe/obj\"\n  Compiled-objects .mod directory: \"exe/mod\"\nCompiler options\n  Vendor: \"gnu\"\n  Compiler command: \"gfortran\"\n  Module directory switch: \"-J\"\n  Compiling flags: \"-c -frealloc-lhs -std=f2008 -fall-intrinsics -O2 -Dr16p\"\n  Linking flags: \"-O2\"\n  Preprocessing flags: \"-Dr16p\"\n  Coverage: False\n  Profile: False\nPreForM.py used: False\nPreForM.py output directory: None\nPreForM.py extensions processed: []\n\nBuilding src/tests/is_real.f90\nCompiling src/lib/penf.F90 serially\nCompiling src/lib/string_t.F90 serially\nCompiling src/lib/stringifor.F90 serially\nCompiling src/tests/is_real.f90 serially\nLinking exe/is_real\nTarget src/tests/is_real.f90 has been successfully built\nBuilder options\n  Directories\n    Building directory: \"exe\"\n    Compiled-objects .o   directory: \"exe/obj\"\n    Compiled-objects .mod directory: \"exe/mod\"\n  Compiler options\n    Vendor: \"gnu\"\n    Compiler command: \"gfortran\"\n    Module directory switch: \"-J\"\n    Compiling flags: \"-c -frealloc-lhs -std=f2008 -fall-intrinsics -O2 -Dr16p\"\n    Linking flags: \"-O2\"\n    Preprocessing flags: \"-Dr16p\"\n    Coverage: False\n    Profile: False\n  PreForM.py used: False\n  PreForM.py output directory: None\n  PreForM.py extensions processed: []\n\nBuilding src/tests/slen.f90\nCompiling src/tests/slen.f90 serially\n...\n\n→ tree -L 1 exe/\nexe/\n├── assignments\n├── basename_dir\n├── camelcase\n├── capitalize\n├── concatenation\n├── equal\n├── escape\n├── extension\n├── fill\n...\n├── swapcase\n├── to_number\n├── unique\n└── upper_lower\n```\n\n#### Build the library\n\nType\n\n```bash\n# static-linked library by means of GNU gfortran\nFoBiS.py build -mode stringifor-static-gnu\n\n# shared-linked library by means of GNU gfortran\nFoBiS.py build -mode stringifor-shared-gnu\n\n# static-linked library by means of Intel Fortran\nFoBiS.py build -mode stringifor-static-intel\n\n# shared-linked library by means of Intel Fortran\nFoBiS.py build -mode stringifor-shared-intel\n```\n\nThe library will be built into the directory `./lib`.\n\n### List other fobos modes\n\nTo list all *fobos-provided* modes type\n\n```bash\n→ FoBiS.py build -lmodes\nThe fobos file defines the following modes:\n  - \"tests-gnu\"\n  - \"tests-gnu-debug\"\n  - \"tests-intel\"\n  - \"tests-intel-debug\"\n  - \"stringifor-static-gnu\"\n  - \"stringifor-shared-gnu\"\n  - \"stringifor-static-intel\"\n  - \"stringifor-shared-intel\"\n```\n\nIt is worth to note that the first mode is the one automatically called by `FoBiS.py build`.\n\n### Build by means of GNU Make\n\nThe provided makefile support only static-linked library building (not shared one) with both Intel Fortran Compiler and GNU gfortran, and it has two main building rules:\n\n+ build the (static linked) library;\n+ build the tests suite.\n\n\u003e the GNU gfortran compiler is the default one, but the compiler used can be customized with COMPILER=#vendor switch.\n\nTo build the library type with the GNU gfortran compiler.\n\n```bash\nmake\n```\n\nThe library will be built into the directory `./lib/libstringifor.a`.\n\nTo build the tests suite type\n\n```bash\nmake TESTS=yes\n```\n\nThe tests will be built into the directory `./exe`.\n\nIf you want to use Intel Fortran Compiler add the switch `COMPILER=intel` to the above commands, i.e.\n\n```bash\nmake COMPILER=intel # build only the library\nmake COMPILER=intel TESTS=yes # build the tests suite\n```\n\n### Build by means of CMake\n\nTo be done.\n\nGo to [Top](#top)\n\n---\n\n## Documentation\n\nThe StringiFor documentation is mainly contained into this file (it has its own [wiki](https://github.com/szaghi/StringiFor/wiki) with some less important documents). Detailed documentation of the API is contained into the [GitHub Pages](http://szaghi.github.io/StringiFor/index.html) that can also be created locally by means of [ford tool](https://github.com/cmacmackin/ford).\n\n---\n\n### Methods API\n\nIn the following all the methods of `string` are listed with a brief description of their aim. The hyperlinks bring you to the full API explained into the GH pages.\n\n##### built-ins replacements\n\n| name                 | meaning             |\n|----------------------|---------------------|\n|[adjustl ](#adjustl ) | adjustl replacement |\n|[adjustr ](#adjustr ) | adjustr replacement |\n|[count   ](#count   ) | count replacement   |\n|[index   ](#index   ) | index replacement   |\n|[len     ](#len     ) | len replacement     |\n|[len_trim](#len_trim) | len_trim replacement|\n|[repeat  ](#repeat  ) | repeat replacement  |\n|[scan    ](#scan    ) | scan replacement    |\n|[trim    ](#trim    ) | trim replacement    |\n|[verify  ](#verify  ) | verify replacement  |\n\n##### auxiliary methods\n\n| name                                                                 | meaning                                                                          |\n|----------------------------------------------------------------------|----------------------------------------------------------------------------------|\n|[basedir    ](http://szaghi.github.io/StringiFor/proc/basedir.html  ) | return the base directory name of a string containing a file name                |\n|[basename   ](http://szaghi.github.io/StringiFor/proc/basename.html ) | return the base file name of a string containing a file name                     |\n|[camelcase  ](http://szaghi.github.io/StringiFor/proc/camelcase.html) | return a string with all words capitalized without spaces                        |\n|[capitalize ](#capitalize                                           ) | return a string with its first character capitalized and the rest lowercased     |\n|[chars      ](#chars                                                ) | return the raw characters data                                                   |\n|[decode     ](#decode                                               ) | decode string                                                                    |\n|[encode     ](#encode                                               ) | encode string                                                                    |\n|[escape     ](#escape                                               ) | escape backslashes (or custom escape character)                                  |\n|[extension  ](#extension                                            ) | return the extension of a string containing a file name                          |\n|[fill       ](#fill                                                 ) | pad string on the left (or right) with zeros (or other char) to fill width       |\n|[free       ](#free                                                 ) | free dynamic memory                                                              |\n|[insert     ](#insert                                               ) | insert substring into string at a specified position                             |\n|[join       ](#join                                                 ) | return a string that is a join of an array of strings or characters              |\n|[lower      ](#lower                                                ) | return a string with all lowercase characters                                    |\n|[partition  ](#partition                                            ) | split string at separator and return the 3 parts (before the separator and after)|\n|[read_file  ](#read_file                                            ) | read a file a single string stream                                               |\n|[read_line  ](#read_line                                            ) | read line (record) from a connected unit                                         |\n|[read_lines ](#read_lines                                           ) | read (all) lines (records) from a connected unit as a single ascii stream        |\n|[replace    ](#replace                                              ) | return a string with all occurrences of substring old replaced by new            |\n|[reverse    ](#reverse                                              ) | return a reversed string                                                         |\n|[search     ](#search                                               ) | search for *tagged* record into string                                           |\n|[slice      ](#slice                                                ) | return the raw characters data sliced                                            |\n|[snakecase  ](#snakecase                                            ) | return a string with all words lowercase separated by *_*                        |\n|[split      ](#split                                                ) | return a list of substring in the string using sep as the delimiter string       |\n|[startcase  ](#startcase                                            ) | return a string with all words capitalized, e.g. title case                      |\n|[strip      ](#strip                                                ) | return a string with the leading and trailing characters removed                 |\n|[swapcase   ](#swapcase                                             ) | return a string with uppercase chars converted to lowercase and vice versa       |\n|[tempname   ](#tempname                                             ) | return a safe temporary name suitable for temporary file or directories          |\n|[to_number  ](#to_number                                            ) | cast string to number                                                            |\n|[unescape   ](#unescape                                             ) | unescape double backslashes (or custom escaped character)                        |\n|[unique     ](#unique                                               ) | reduce to one (unique) multiple occurrences of a substring into a string         |\n|[upper      ](#upper                                                ) | return a string with all uppercase characters                                    |\n|[write_file ](#write_file                                           ) | write a single string stream into file                                           |\n|[write_line ](#write_line                                           ) | write line (record) to a connected unit                                          |\n|[write_lines](#write_lines                                          ) | write lines (records) to a connected unit                                        |\n\n##### inquire methods\n\n| name                         | meaning                                                      |\n|------------------------------|--------------------------------------------------------------|\n|[end_with    ](#end_with    ) | return true if a string ends with a specified suffix         |\n|[is_allocated](#is_allocated) | return true if the string is allocated                       |\n|[is_digit    ](#is_digit    ) | return true if all characters in the string are digits       |\n|[is_integer  ](#is_integer  ) | return true if the string contains an integer                |\n|[is_lower    ](#is_lower    ) | return true if all characters in the string are lowercase    |\n|[is_number   ](#is_number   ) | return true if the string contains a number (real or integer)|\n|[is_real     ](#is_real     ) | return true if the string contains an real                   |\n|[is_upper    ](#is_upper    ) | return true if all characters in the string are uppercase    |\n|[start_with  ](#start_with  ) | return true if a string starts with a specified prefix       |\n\n##### operators\n\n| name                     | meaning                                                       |\n|--------------------------|---------------------------------------------------------------|\n|[assignment](#assignment) | assignment of string from different inputs                    |\n|[//        ](#//        ) | concatenation resulting in characters for seamless integration|\n|[.cat.     ](#.cat.     ) | concatenation resulting in `string`                           |\n|[==        ](#==        ) | equal operator                                                |\n|[/=        ](#/=        ) | not equal operator                                            |\n|[\u003c         ](#\u003c         ) | lower than operator                                           |\n|[\u003c=        ](#\u003c=        ) | lower equal than operator                                     |\n|[\u003e=        ](#\u003e=        ) | greater equal than operator                                   |\n|[\u003e         ](#\u003e         ) | greater than operator                                         |\n\n##### IO\n\n| name                                    | meaning           |\n|-----------------------------------------|-------------------|\n|[read(formatted)   ](#read_formatted   ) | formatted input   |\n|[write(formatted)  ](#write_formatted  ) | formatted output  |\n|[read(unformatted) ](#read_unformatted ) | unformatted input |\n|[write(unformatted)](#write_unformatted) | unformatted output|\n\nGo to [Top](#top)\n\n---\n\n## Comparison to other Approaches\n\nThe lack of Fortran support for strings manipulation has promoted different solutions in the past years. Following the classification of Clive Page [[1]](#clive-page-talk) we can consider:\n\n+ standard character type;\n+ deferred-length allocatable character type (standard 2003+);\n+ `VARYING_STRING` type (standard 90/95+) as defined in ISO/IEC 1539-2:2000 (Varying length character strings).\n\nLet us compare StringiFor to the previous three approaches. In particular, let us consider Ian Harvey extension of `VARYING_STRING`, i.e. the `aniso_varying_string` [[2]](#aniso_vstring).\n\nClive Page had pointed out the following issues, among the others:\n\n+ fixed (at compile time) string length\n```fortran\ncharacter(len=3) :: astring ! further lengths different from 3 are not allowed\n```\n+ silent truncation on assignment\n```fortran\ncharacter(len=3) :: astring\nastring = 'abcdefgh' ! silent trunctation at 'abc'\n```\n+ trim-cluttered code\n```fortran\ncharacter(len=99) :: astring\ncharacter(len=99) :: anotherstring\nastring = 'abcdefgh'\nanotherstring = trim(astring)//'ilmnopqrst' ! trim-cluttering is a necessity\n```\n+ handle significant trailing spaces\n```fortran\ncharacter(len=99) :: astring\ncharacter(len=99) :: anotherstring\nastring = 'Hello ' ! for some reasons you want to keep these trailing white spaces\nanotherstring = trim(astring)//'World' ! you need trim because\n                                       ! len(astring)==len(anotherstring), but lost the significant\n                                       ! trailing spaces...\n```\n+ different character definition\n```fortran\ncharacter         :: astring*10    ! old way\ncharacter(len=10) :: anotherstring ! new way\n```\n+ allocation of array of strings\n```fortran\ncharacter(len=10), allocatable :: astring(:)\nallocate(astring(100)) ! all 100 elements of the array have 10 characters,\n                       ! different lengths cannot be declared\n```\n+ initialization of array of strings\n```fortran\n! the following is illegal\ncharacter(len=9), parameter :: day(7) = ['Monday',    \u0026\n                                         'Tuesday',   \u0026\n                                         'Wednesday', \u0026\n                                         'Thursday',  \u0026\n                                         'Friday',    \u0026\n                                         'Saturday',  \u0026\n                                         'Sunday']\n! the following is legal, but cluttered by non significant trailing spaces\ncharacter(len=9), parameter :: day(7) = ['Monday   ', \u0026\n                                         'Tuesday  ', \u0026\n                                         'Wednesday', \u0026\n                                         'Thursday ', \u0026\n                                         'Friday   ', \u0026\n                                         'Saturday ', \u0026\n                                         'Sunday']\n```\n+ IO limitations for non standard character variables\n```fortran\ncharacter(len=99)             :: astring\ncharacter(len=:), allocatable :: anotherstring\ntype(varying_string)          :: yetanotherstring\n! fully-simple support for standard character variables\nastring = 'abcdefgh'\nprint*, astring\nprint \"(A)\", astring\nread(10, *) astring\n! partial-simple support for standard deferred length-length allocatable character variables\n! care must be placed in input operation...\nprint*, anotherstring\nprint \"(A)\", anotherstring\nread(10, *) anotherstring\n! support depends on the implementation of the varying string type\nprint*, yetanotherstring\nprint \"(DT)\", yetanotherstring\nread(10, *) yetanotherstring\n```\n+ substring notation (slice)  for non standard character variables\n```fortran\ncharacter(len=99)             :: astring\ncharacter(len=:), allocatable :: anotherstring\ntype(varying_string)          :: yetanotherstring\nastring = 'abcdefgh'\nyetanotherstring = astring\nanotherstring = astring(2:6)          ! allowed\nanotherstring = yetanotherstring(2:6) ! not allowed\n```\n+ passing string to procedures expecting standard character argument is *complicated*\n\nAnalyzing the above issues we can agree that deferred-length allocatable character and aniso_varyng_string approaches address many of them, at the cost of introducing some oddies.\n\n#### deferred-length allocatable character\n\nThis approaches addresses all the issues related to the fixed length limitation, e.g.\n```fortran\ncharacter(len=:), allocatable :: astring\ncharacter(len=:), allocatable :: anotherstring\nastring = 'Hello '\nanotherstring = astring//'World' ! trailing with spaces of astring correctly handled\n                                 ! no need of trim\n```\n\nHowever, it has some limitations too. Aside the input operation, the most important (IMHO) are related to arrays of strings handling, e.g.\n```fortran\ncharacter(len=:), allocatable :: asetofstring(:)\nallocate(character(len=99) :: asetofstring(10)) ! all 10 elements must have len=99\n```\n\n#### aniso_varying_string\n\nAniso_varying_string is an implemention of ISO/IEC 1539-2:2000 (Varying length character strings) developed by Ian Harvey that is internally based on a deferred-lenght allocatable character variable: it is essentially a derived type wrapping a deferred-lenght allocatable character. As a consequence, it has all the advantages of the deferred-length allocatable character approach. The wrapping approach addresses the arrays related issues, e.g.\n```fortran\ntype(varying_string), allocatable :: asetofstring(:)\nallocate(asetofstring(10)) ! all 10 elements can have diffent lengths\n```\nIts major issues are related to IO operations: however, this is addressed by new Fortran support for defined IO for derived type that make more effortless the IO of such an object. The other main issue is the impossibility to use the standard slice notation to access to substring: aniso_varying_string addresses (partially) this issue by public-exposing the wrapped allocatable character of its implementations thus allowing the slicing of it, e.g.\n```fortran\ntype(varying_string) :: astring\nastring = 'abcdefg'\nprint \"(A)\", astring%chars(2:3) ! print 'bc'\n```\n\n#### StringiFor\n\nStringiFor shares the same philosophy of aniso_varying_string, thut it has the same pros and cons. However, StringiFor is an Object Oriented Designed class, thus it has some peculiariaties distinguishing it from aniso_varying_string, see [StringiFor Peculiarities](#stringifor-peculiarities).\n\n#### Comparison results\n\nThe following table summarizes the comparison analysis.\n\n| issue                       | standard character | deferred-length allocatable character | aniso_varying_string | StringiFor         |\n|-----------------------------|--------------------|---------------------------------------|----------------------|--------------------|\n| fixed length                | :cloud:            | :sunny:                               | :sunny:              | :sunny:            |\n| silent trunction            | :cloud:            | :sunny:                               | :sunny:              | :sunny:            |\n| trim-clutter                | :cloud:            | :sunny:                               | :sunny:              | :sunny:            |\n| significant trailing spaces | :cloud:            | :sunny:                               | :sunny:              | :sunny:            |\n| different string definition | :cloud:            | :cloud:                               | :sunny:              | :sunny:            |\n| array allocatation          | :cloud:            | :cloud:                               | :sunny:              | :sunny:            |\n| array initialization        | :cloud:            | :cloud:                               | :sunny:              | :sunny:            |\n| IO                          | :sunny:            | :sunny:                               | :partly_sunny:       | :partly_sunny:     |\n| substring (slice) notation  | :sunny:            | :sunny:                               | :partly_sunny:       | :partly_sunny:     |\n| Fortran builtins            | :sunny:            | :sunny:                               | :partly_sunny:       | :partly_sunny:     |\n\n##### legend\n|  symbol        | meaning           |\n|----------------|-------------------|\n| :cloud:        | bad or no support |\n| :partly_sunny: | partial support   |\n| :sunny:        | good support      |\n\n### StringiFor Peculiarities\n\nStringiFor publics an OOD class, the `string` object. This class is aimed to address all the issues of the standard character type, as ISO Varying String approaches do, but it is also designed to provide a features-rich string object as you can find on other languages like Python. As a matter of facts, the *auxiliary methods* added to the `string` object consitute a long list of new (for Fortraners) string-facilities, allowing you to handle strings effortless (cases-conversion, files-handling, encode/decode, numbers-casting, etc...), see the complete [API](#methods-api). It is worth to note that StringiFor is a tentative to adopt an fully OOD thus all methods and operators are TBP defined: to use StringiFor you can import only the `string` type, allowing a sane and robust names space handling. Only in the case you want the Fortran builtins to accept a `string` instead of a standard character type, e.g. to use `index(astring, 'c')` seamless with both a `type(string) :: astring` and a `character(99) :: astring`, you must use all the StringiFor public objects, including the overloaded interfaces of the Fortran builtins.\n\n#### References\n\n[1]\u003ca name=\"clive-page-talk\"\u003e\u003c/a\u003e [*Improved String-handling in Fortran*](http://www.fortran.bcs.org/2015/suggestion_string_handling.pdf), Clive Page, October 2015.\n\n[2]\u003ca name=\"aniso_vstring\"\u003e\u003c/a\u003e [*aniso_varying_string*](http://www.megms.com.au/aniso_varying_string.htm), Ian Harvey, 2016.\n\nGo to [Top](#top)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fszaghi%2Fstringifor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fszaghi%2Fstringifor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fszaghi%2Fstringifor/lists"}