Skip to content

Commit e183560

Browse files
committed
main
1 parent d58a517 commit e183560

File tree

2 files changed

+276
-2
lines changed

2 files changed

+276
-2
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Google Hack Syntax
2+
3+
## Operators
4+
5+
- `NOT` or `-`: exclude a word from search result
6+
- `OR` or `|`: match one of the phrase, `foo | bar | baz`
7+
- `"<phrase>"`: exact match
8+
- `()`: group any expression
9+
```txt
10+
# foo is mandatory, bar and baz are optional
11+
foo (bar | baz)
12+
```
13+
- `.`: any character
14+
- `*`: any phrase
15+
16+
> [!TIP]
17+
> Use `""` to represent raw string when you need to contain any special character above in your query
18+
19+
## Keywords
20+
21+
> [!NOTE]
22+
> Do not leave spaces between keyword operator and the followed query
23+
> You can use exact match `""` after keyword operator
24+
> Wildcard not allowed in query after keyword operator
25+
26+
> not a exhaustive list but practical enough
27+
28+
- `intitle:`: contains phrase in title
29+
- `inurl:`: match phrase in page url
30+
- `intext:`: match phrase in `<body>` section of a page
31+
- `inanchor:`: match links of anchors in the page
32+
- `site:`: match by top-level domain
33+
- `cache:`: finds snapshot of page, specify url after it
34+
- `filetype:`: specify only one filetype, use `OR` if multiple filetypes are desired
35+
36+
## Best Practice
37+
38+
Ordering your query by `<normal query>[<operator options>][<keyword options>]` would be the best practice
39+
40+
```
41+
I need foo -bar site:foo intitle:foo
42+
```

docs/document/Modern CSharp/docs/Understanding String Formatting.md

Lines changed: 234 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ string.Format("{0,-20}", 123);
5151
- supported for `Double`, `Single`, `Half` and `BigInteger` only.
5252
- ensures the converted string represents the exact precision of the number.
5353

54-
#### Arbitrary Format Composition
54+
### Arbitrary Numeric Format Composition
5555

5656
Composite formatting supports a dedicated syntax to represent any numeric format by following convention
5757

@@ -84,7 +84,239 @@ Composite formatting supports a dedicated syntax to represent any numeric format
8484
```
8585
- `\` to escape any special character above
8686

87-
## `ToString` & `IFormattable`
87+
### DateTime Format
8888

89+
> [!NOTE]
90+
> See [standard datetime format](https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings) and [Arbitrary datetime format](https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings)
91+
92+
### TimeSpan Format
93+
94+
> [!NOTE]
95+
> See [standard TimeSpan format](https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-timespan-format-strings#the-general-long-g-format-specifier) and [Arbitrary TimeSpan format](https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-timespan-format-strings)
96+
97+
## How to Support a Custom Format
98+
99+
Before we implement a custom process for our format, we have to understand the common interfaces for formatting.
100+
101+
### `IFormatProvider`
102+
103+
`System.IFormatProvider` acts like a wrapper to cover generic solution for formatting.
104+
The return type is `object` which means the *format* to be returned here can be any kind of representation, the use is really dependent on the method that uses the `IFormatProvider`.
105+
The *format* object returned may contain some **culture-related information**, such as negative sign for numerics. And the object is usually a `IFormatProvider` too.
106+
107+
```cs
108+
public interface IFormatProvider
109+
{
110+
object? GetFormat(Type? formatType);
111+
}
112+
```
113+
114+
The parameter is the type of the type should handle the *format* so we can return different formatting solution for different kinds of values.
115+
That is to say, we commonly have a conditional statement inside the implementation of `IFormatProvider.GetFormat`.
116+
117+
`CultureInfo` is typically a `IFormatProvider` that hanles numeric and datetime in `IFormatProvider.GetFormat(Type? type)`
118+
119+
```cs
120+
// implementation in CultureInfo
121+
public virtual object? GetFormat(Type? formatType)
122+
{
123+
if (formatType == typeof(NumberFormatInfo))
124+
{
125+
return NumberFormat; // [!code highlight]
126+
}
127+
if (formatType == typeof(DateTimeFormatInfo))
128+
{
129+
return DateTimeFormat;
130+
}
131+
132+
return null;
133+
}
134+
135+
// where NumberFormat is a process to generate a NumerFormatInfo based on Culture
136+
public virtual NumberFormatInfo NumberFormat
137+
{
138+
get
139+
{
140+
if (_numInfo == null)
141+
{
142+
NumberFormatInfo temp = new NumberFormatInfo(_cultureData); // [!code highlight]
143+
temp._isReadOnly = _isReadOnly;
144+
Interlocked.CompareExchange(ref _numInfo, temp, null);
145+
}
146+
return _numInfo!;
147+
}
148+
set
149+
{
150+
ArgumentNullException.ThrowIfNull(value);
151+
152+
VerifyWritable();
153+
_numInfo = value;
154+
}
155+
}
156+
```
157+
158+
The actual usage of `GetFormat` inside the caller method is like
159+
160+
```cs
161+
var provider = new CultureInfo("en-US");
162+
var format = (NumberFormatInfo)provider.GetFormat(typeof(NumberFormatInfo));
163+
```
164+
165+
It's kind of strange that you already know the type of *format* but still, it's just an identification on what kind of the handler should be returned.
166+
And the `Type` should be the optimal solution since we don't know what would be formatted anyway, so we can't say there can here a enumeration as parameter.
167+
168+
### `ICustomFormatter`
169+
170+
Implementing `ICustomFormatter` means the type can handle formatting for a single value as a external handler
171+
172+
- `format`: the format for the value
173+
- `arg`: the value
174+
- `formatProvider`: provider for formatting
175+
176+
```cs
177+
public interface ICustomFormatter
178+
{
179+
string Format(string? format, object? arg, IFormatProvider? formatProvider);
180+
}
181+
```
182+
183+
We always implement both `IFormatProvider` and `ICustomFormatter` if you want to customize your own format for any type(even existing types since `ICustomFormatter` has higher priority)
184+
**That is because composite formatting methods only accepts `IFormatProvider` as an variant supplier**, it's a good practice to do it in a same type.
185+
And the identity as a `ICustomFormatter` should always be provided from `IFormatProvider.GetFormat`
186+
187+
The way to retrieve a `ICustomFormatter` inside a composite formatting method is like
188+
189+
```cs
190+
ICustomFormatter? cf = (ICustomFormatter?)provider?.GetFormat(typeof(ICustomFormatter)); // [!code highlight]
191+
// .. a super long process to parse the whole format string
192+
if (cf != null)
193+
{
194+
s = cf.Format(itemFormat, arg, provider); // [!code highlight]
195+
}
196+
```
197+
198+
> [!NOTE]
199+
> `typeof(ICustomFormatter)` is the only possible identification here, because it's a custom, external way.
200+
201+
While in the implementation side, the `ICustomFormatter` should be returned in `IFormatProvider.GetFormat` just like
202+
203+
```cs
204+
class CustomFormatter : IFormatProvider, ICustomFormatter
205+
{
206+
public object GetFormat(Type? formatType)
207+
{
208+
if (formatType == typeof(ICustomFormatter))
209+
return this; // [!code highlight]
210+
else
211+
{
212+
// ... handle other types
213+
}
214+
}
215+
216+
public string Format(string? format, object? arg, IFormatProvider? formatProvider)
217+
{
218+
Type? type = arg?.GetType();
219+
if (type == typeof(long))
220+
{
221+
//...
222+
}
223+
else if (type == typeof(int))
224+
{
225+
// ...
226+
}
227+
}
228+
}
229+
```
230+
231+
### `IFormattable`
232+
233+
Implementing `IFormattable` means the type itself can handle the formatting for the value it represents.
234+
235+
- `format`: the format for the value
236+
- `formatProvider`: provider used for the formatting
237+
238+
```cs
239+
public interface IFormattable
240+
{
241+
string ToString(string? format, IFormatProvider? formatProvider);
242+
}
243+
```
244+
245+
```cs
246+
class CustomObject : IFormattable
247+
{
248+
249+
public string ToString(string format, IFormatProvider? provider)
250+
{
251+
if (String.IsNullOrEmpty(format)) format = "G"; // use G as general // [!code highlight]
252+
provider ??= CultureInfo.CurrentCulture; // [!code highlight]
253+
254+
switch (format.ToUpperInvariant()) // [!code highlight]
255+
{
256+
case "G":
257+
case "C":
258+
case "F":
259+
case "K":
260+
default:
261+
throw new FormatException(string.Format("The {0} format string is not supported.", format));
262+
}
263+
}
264+
}
265+
```
89266

90267
## Formatting Strategy
268+
269+
We already knew that the approaches how dotnet handles formatting for builtin types and custom types.
270+
Those solutions are all tried on methods like `string.Format` with following order.
271+
272+
- If the value to be formatted is `null`, returns `string.Empty`
273+
- If the `IFormatProvider` secified is `ICustomFormatter`, `ICustomFormatter.Format(string? fmt, IFormatProvider? fmtProvider)` would be called
274+
- If `ICustomFormatter.Format` returns `null` for current value, steps into next solution.
275+
- If `IFormatProvider` is specified
276+
- If the value is `IFormattable`, `IFormattable.ToString(string fmt, IFormatProvider? fmtProvider)` is called
277+
- `object.ToString` or overrided version was called if all approaches above are failed.
278+
279+
```cs
280+
ICustomFormatter? cf = (ICustomFormatter?)provider?.GetFormat(typeof(ICustomFormatter)); // [!code highlight]
281+
282+
string? s = null;
283+
284+
if (cf != null)
285+
{
286+
if (!itemFormatSpan.IsEmpty)
287+
{
288+
itemFormat = new string(itemFormatSpan);
289+
}
290+
s = cf.Format(itemFormat, arg, provider); // [!code highlight]
291+
}
292+
293+
if (s == null) // if ICustomFormatter.Format returns null // [!code highlight]
294+
{
295+
// If arg is ISpanFormattable and the beginning doesn't need padding,
296+
// try formatting it into the remaining current chunk.
297+
if ((leftJustify || width == 0) &&
298+
arg is ISpanFormattable spanFormattableArg &&
299+
spanFormattableArg.TryFormat(_chars.Slice(_pos), out int charsWritten, itemFormatSpan, provider))
300+
{
301+
// ..
302+
}
303+
304+
if (arg is IFormattable formattableArg) // [!code highlight]
305+
{
306+
if (itemFormatSpan.Length != 0)
307+
{
308+
itemFormat ??= new string(itemFormatSpan);
309+
}
310+
s = formattableArg.ToString(itemFormat, provider); // [!code highlight]
311+
}
312+
else
313+
{
314+
s = arg?.ToString(); // object.ToString as the last resort // [!code highlight]
315+
}
316+
317+
s ??= string.Empty; // if all solution were tried but still null // [!code highlight]
318+
}
319+
```
320+
321+
> [!NOTE]
322+
> `ISpanFormattable` is a more advance topic since .NET 6.

0 commit comments

Comments
 (0)