1 module des.stdx..string;
2 
3 public import std..string;
4 
5 import std.array;
6 import std.algorithm;
7 import std.traits;
8 import std.range;
9 
10 import des.ts;
11 import des.stdx.type : getTypedArray;
12 
13 public import des.stdx.pformat;
14 
15 ///
16 string toSnakeCase( in string str, bool ignore_first=true ) @property pure @trusted
17 {
18     string[] buf;
19     buf ~= "";
20     foreach( i, ch; str )
21     {
22         if( [ch].toUpper == [ch] ) buf ~= "";
23         buf[$-1] ~= [ch].toLower;
24     }
25     if( buf[0].length == 0 && ignore_first )
26         buf = buf[1..$];
27     return buf.join("_");
28 }
29 
30 ///
31 unittest
32 {
33     assertEq( "SomeVar".toSnakeCase, "some_var" );
34     assertEq( "SomeVar".toSnakeCase(false), "_some_var" );
35 
36     assertEq( "someVar".toSnakeCase, "some_var" );
37     assertEq( "someVar".toSnakeCase(false), "some_var" );
38 
39     assertEq( "ARB".toSnakeCase, "a_r_b" );
40     assertEq( "ARB".toSnakeCase(false), "_a_r_b" );
41 
42     // not alphabetic chars in upper case looks like lower, func separate by them
43     assertEq( "A.B.r.A".toSnakeCase, "a_._b_.r_._a" );
44     assertEq( "A_B_r_A".toSnakeCase, "a___b__r___a" );
45 }
46 
47 ///
48 string toCamelCaseBySep( in string str, string sep="_", bool first_capitalize=true ) pure @trusted
49 {
50     auto arr = array( filter!"a.length > 0"( str.split(sep) ) );
51     string[] ret;
52     foreach( i, v; arr )
53     {
54         auto bb = v.capitalize;
55         if( i == 0 && !first_capitalize )
56             bb = v.toLower;
57         ret ~= bb;
58     }
59     return ret.join("");
60 }
61 
62 ///
63 unittest
64 {
65     assertEq( toCamelCaseBySep( "single-precision-constant", "-", false ), "singlePrecisionConstant" );
66     assertEq( toCamelCaseBySep( "one.two.three", ".", true ), "OneTwoThree" );
67     assertEq( toCamelCaseBySep( "one..three", ".", true ), "OneThree" );
68     assertEq( toCamelCaseBySep( "one/three", "/" ), "OneThree" );
69     assertEq( toCamelCaseBySep( "one_.three", ".", false ), "one_Three" );
70 
71     // `_` in upper case looks equals as lower case
72     assertEq( toCamelCaseBySep( "one._three", ".", true ), "One_three" );
73 }
74 
75 ///
76 string toCamelCase( in string str, bool first_capitalize=true ) @property pure @trusted
77 { return toCamelCaseBySep( str, "_", first_capitalize ); }
78 
79 ///
80 unittest
81 {
82     assertEq( "some_class".toCamelCase, "SomeClass" );
83     assertEq( "_some_class".toCamelCase, "SomeClass" );
84     assertEq( "some_func".toCamelCase(false), "someFunc" );
85     assertEq( "_some_func".toCamelCase(false), "someFunc" );
86     assertEq( "a_r_b".toCamelCase, "ARB" );
87     assertEq( toCamelCase( "program_build" ), "ProgramBuild" );
88     assertEq( toCamelCase( "program__build" ), "ProgramBuild" );
89 
90     assertEq( toCamelCase( "program__build", false ), toCamelCaseBySep( "program__build", "_", false ) );
91 }
92 
93 /// copy chars to string
94 string toDString( const(char*) c_str ) nothrow pure @trusted
95 {
96     if( c_str is null ) return "";
97     char *ch = cast(char*)c_str;
98     size_t n;
99     while( *ch++ != '\0' ) n++;
100     return getTypedArray!char( n, c_str ).idup;
101 }
102 
103 ///
104 unittest
105 {
106     auto c = [ 'a', 'b', 'c', '\0', 'd', 'e' ];
107     assertEq( toDString( c.ptr ), "abc" );
108 }
109 
110 /// ditto
111 string toDStringFix(size_t S)( const(char[S]) c_buf ) nothrow pure @trusted
112 {
113     size_t n;
114     foreach( c; c_buf )
115     {
116         if( c == '\0' ) break;
117         n++;
118     }
119     return getTypedArray!char( n, c_buf.ptr ).idup;
120 }
121 
122 ///
123 unittest
124 {
125     char[6] c = [ 'a', 'b', 'c', '\0', 'd', 'e' ];
126     assertEq( toDStringFix(c), "abc" );
127 }